CMake pkg-config Mode: Version - c++

I am trying to use the CMake --find-package mode to verify in a one-liner if a usable version of boost exists.
This can generally be done via
cmake --find-package -DNAME=Boost -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST
but I would like to know the if a minimal version was found.
For example in a CMakeList.txt this would read
find_package(Boost 1.60.0)
I tried to encode it in the -DNAME, searched the web for the problem and tried to guess a variable like -DMINVERSION but could not find a solution or documentation entry that describes further options.
A current work-around I am using looks like this
echo -e "#include <boost/version.hpp>\n#include <iostream>\n" \
"int main() { std::cout << BOOST_VERSION << std::endl; return 0; }" \
| g++ -I$BOOST_ROOT/include -x c++ - || { echo 0; }
BOOST_FOUND=$([ $(./a.out) -ge 106000 ] && { echo 0; } || { echo 1; })

Related

C++ CodeBlocks upgrade to C++17 can't use std::filesystem

I need to be able to list the files in a directory, and so I'm trying to upgrade my C++ version in CodeBlocks to C++ 17 so i can use filesystem. To do this I followed the steps outlined at http://candcplusplus.com/enable-c17-in-code-blocks-mingw-gcc-for-all-version-with-pictures#:~:text=Enabling%20the%20C%2B%2B17,Create%20a%20project.
I didnt have to change much, CodeBlocks 20.03 and MinGW 8.1.0 are already installed. MinGW is already in my path from when I built wxWidgets. The Settings->Compiler...->Toolchain executables tab I didnt have to make any changes to, and appears in CodeBlocks as:
I also checked the box to use C++ 17 in compiler settings like so
I ran the test program on the website with the instructions and got "True!".
However when I change the basic test program to this, to try and use filesystem to read files in a directory, I get an error:
#include <iostream>
#include <filesystem>
using namespace std;
int main()
{
const int i=90;
if constexpr (i) //'if constexpr' is part of C++17
{
cout << "True!";
}
else
{
cout<<"False" ;
}
std::string path = "../MagicProgCPP/files/debug images/";
for (const auto & entry : filesystem::directory_iterator(path))
{
cout << entry.path() << std::endl;
}
cin.get();
return 0;
}
The program stops building, opens the file fs_path.h and stops on this line:
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (__p.is_absolute()
|| (__p.has_root_name() && __p.root_name() != root_name())) <----- ******STOPS HERE
operator=(__p);
else
{
string_type __pathname;
if (__p.has_root_directory())
__pathname = root_name().native();
else if (has_filename() || (!has_root_directory() && is_absolute()))
__pathname = _M_pathname + preferred_separator;
__pathname += __p.relative_path().native(); // XXX is this right?
_M_pathname.swap(__pathname);
_M_split_cmpts();
}
#else
// Much simpler, as any path with root-name or root-dir is absolute.
if (__p.is_absolute())
operator=(__p);
else
{
if (has_filename() || (_M_type == _Type::_Root_name))
_M_pathname += preferred_separator;
_M_pathname += __p.native();
_M_split_cmpts();
}
#endif
return *this;
}
I get this error in the build log:
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\fs_path.h|237|error: no match for 'operator!=' (operand types are 'std::filesystem::__cxx11::path' and 'std::filesystem::__cxx11::path')|
I'm prety confident the path exists as I entered it and there's files in it. The build log message suggests maybe I'm not using C++17? But when I click build, this is the line the program uses to build:
g++.exe -Wall -fexceptions -g -Wall -std=c++17 -c E:\testc17\main.cpp -o obj\Debug\main.o
What am I doing wrong? Thanks
The bug 78870 was fixed since 2018-07.
You should add to project options -> linker settings -> link libraries the following library: stdc++fs.
I tried to compile your code with MinGW gcc 8.1.0 (via CodeBlocks) and everything works well (clearly with another path, since I don't have the same directories as you).
You could also add a check on the existence of the search directory like this:
namespace fs = std::filesystem;
std::string mypath { "../MyDir" };
if(fs::exists(mypath))
{
for(const auto & entry : fs::directory_iterator(path))
{
cout << entry.path() << std::endl;
}
}
It appears that this exact problem is a known bug in mingw 8.1. The bug report is here: https://sourceforge.net/p/mingw-w64/bugs/737/
and has the error in the same location:
operator != is declared and defined in line 550, but referenced in line 237.
The problem is triggered by operator/= in line 233:
path& operator/=(const path& __p)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (__p.is_absolute()
|| (__p.has_root_name() && __p.root_name() != root_name()))
operator=(__p);
else
{
string_type __pathname;
if (__p.has_root_directory())
__pathname = root_name().native();
else if (has_filename() || (!has_root_directory() && is_absolute()))
__pathname = _M_pathname + preferred_separator;
__pathname += __p.relative_path().native(); // XXX is this right?
_M_pathname.swap(__pathname);
_M_split_cmpts();
}
The bug report said this was fixed in master meaning you need to install a version of mingw with the fix applied. I believe the best method is to upgrade mingw to a version greater than 8.1
user4581301 commented above in the main question that the following link has instructions on how to get a mingw install: How to install MinGW-w64 and MSYS2?

Bash autocomplete an option without running the application

I have found this code as a bash autocomplete. But, it looks strange to me. What if I do not like to run the code at all. If I would like to type ./a.out then space (without entering) and then by pressing tab, I would like to see only two options apple and cherry and if I type a and press tab, then it autocomplete the option apple and similarly for c. Let's say only one of the two options are acceptable:
./a.out apple
./a.out cherry
where apple and cherry are options and not the name of the files in the directory. In the first case, I would like the program types that your option is apple and in the second case your option is cherry. In any other case, the program should print an error that the option is not valid.
All examples that I find on the internet such as what follows look like that you should run the program first, then it reacts. The while loop inside the main function collides with the normal functionality of the program. Have I misunderstood the readline library? Is the above-described application possible to implement by editing the following code?
// sudo apt-get install libreadline-dev
// g++ -std=c++11 main.cpp -lreadline
#include <iostream>
#include "readline/readline.h"
#include "readline/history.h"
using namespace std;
int main(int argc, char** argv)
{
const char *line;
while ((line = readline("? ")) != nullptr) {
cout << "[" << line << "]" << endl;
if (*line) add_history(line);
free(line);
}
// if(argc!=2)
// {
// cout<<"<exe> one_parameter"<<endl;
// return 1;
// }
// string option=argv[1];
// if(option=="apple" || option=="cherry")
// cout<<"Your option is "<<option<<endl;
// else
// {
// cout<<"Error: invalid option "<<option<<endl;
// return 1;
// }
return 0;
}
// partial answer - why you may want to invoke the app while doing the autocompletion
One way of implementing the autocomplete for an application is to have the application binary configure it (by having a flag that prints the instructions for autocomplete configuration or by just parsing the --help output of the application).
Schemataically:
complete -F $(./a.out --generate-autocomplete-config) ./a.out
This is why you might see the binary actually invoked as a part of autocomplete implementation.
This has nothing to do with your executable. You need to put this in a file and source (source autocomplete_file or . autocomplete_file) it in the bash.
_a_complete_()
{
local word=${COMP_WORDS[COMP_CWORD]}
local files='apple cherry'
COMPREPLY=( $( compgen -W "${files}" -- ${word} ) )
}
complete -F _a_complete_ ./a.out
Here a nice documentation can be found.

C++ / R: RInside in Windows 7 machine

This question is related to: C++ and R: Create a .so or .dll plus i have read the questions and replies of these posts:
Compiling RInside programs on Windows
Problem with compiling RInside examples under Windows
I try to run the code provided as an example in the answer provided
#include <RInside.h> // for the embedded R via RInside
#include <iomanip>
int main(int argc, char *argv[]) {
RInside R(argc, argv); // create an embedded R instance
std::string txt = // load library, run regression, create summary
"suppressMessages(require(stats));"
"swisssum <- summary(lm(Fertility ~ . , data = swiss));"
"print(swisssum)";
R.parseEvalQ(txt); // eval command, no return
// evaluate R expressions, and assign directly into Rcpp types
Rcpp::NumericMatrix M( (SEXP) R.parseEval("swcoef <- coef(swisssum)"));
Rcpp::StringVector cnames( (SEXP) R.parseEval("colnames(swcoef)"));
Rcpp::StringVector rnames( (SEXP) R.parseEval("rownames(swcoef)"));
std::cout << "\n\nAnd now from C++\n\n\t\t\t";
for (int i=0; i<cnames.size(); i++) {
std::cout << std::setw(11) << cnames[i] << "\t";
}
std::cout << std::endl;
for (int i=0; i<rnames.size(); i++) {
std::cout << std::setw(16) << rnames[i] << "\t";
for (int j=0; j<cnames.size(); j++) {
std::cout << std::setw(11) << M(i,j) << "\t";
}
std::cout << std::endl;
}
std::cout << std::endl;
exit(0);
}
The error in the CMD is the following
C:\Users\DON\Desktop>R CMD SHLIB final.cpp
g++ -m64 -I"C:/R/R-3.2.4/include" -DNDEBUG -I"d:/RCompile/r-compiling/local/
local323/include" -O2 -Wall -mtune=core2 -c final.cpp -o final.o
final.cpp:1:74: fatal error: RInside.h: No such file or directory
compilation terminated.
make: *** [final.o] Error 1
Warning message:
comando ejecutado 'make -f "C:/R/R-3.2.4/etc/x64/Makeconf" -f "C:/R/R-3.2.4/shar
e/make/winshlib.mk" SHLIB_LDFLAGS='$(SHLIB_CXXLDFLAGS)' SHLIB_LD='$(SHLIB_CXXLD)
' SHLIB="final.dll" WIN=64 TCLBIN=64 OBJECTS="final.o"' tiene estatus 2
Clearly it cant find the RInside.h header. I have the R installed in a folder without spaces. The PATH in global variables have: C:\R\R-3.2.4\bin; C:\Rtools\bin;C:\Rtools\gcc-4.6.3\bin
I understand that in the CMD i cant introduce comands like
$ export PKG_LIBS=‘Rscript -e "Rcpp:::LdFlags()"‘ # if Rcpp older than 0.11.0
$ export PKG_CXXFLAGS=‘Rscript -e "Rcpp:::CxxFlags()"‘
Which first defines and exports two relevant environment variables which R CMD SHLIB then relies on (as put in the FAQ file)
Any advice on this? I need to do a Makefile for each cpp file that i want to compile?
The error is in your approach. You did
R CMD SHLIB final.cpp
which is nowhere given as the correct approach for working with RInside.
Because we need to tell R about headers and libraries for several components, you are supposed to
cd inst/examples/standard
make # build all
or
make rinside_sample3 # build just this
or, if you're on that OS,
make -f Makefile.win # all
or
make -f Makefile.win rinside_sample3
as the Makefile tells R where do find this. That also answers your second question: One Makefile per directory will do. And look at the Makefile: it sets several include directives; your approach only dealt with Rcpp so of course you get an error about RInside.h not found.
I think you keep asking the same question over and over.

Run C or C++ file as a script

So this is probably a long shot, but is there any way to run a C or C++ file as a script? I tried:
#!/usr/bin/gcc main.c -o main; ./main
int main(){ return 0; }
But it says:
./main.c:1:2: error: invalid preprocessing directive #!
Short answer:
//usr/bin/clang "$0" && exec ./a.out "$#"
int main(){
return 0;
}
The trick is that your text file must be both valid C/C++ code and shell script. Remember to exit from the shell script before the interpreter reaches the C/C++ code, or invoke exec magic.
Run with chmod +x main.c; ./main.c.
A shebang like #!/usr/bin/tcc -run isn't needed because unix-like systems will already execute the text file within the shell.
(adapted from this comment)
I used it in my C++ script:
//usr/bin/clang++ -O3 -std=c++11 "$0" && ./a.out; exit
#include <iostream>
int main() {
for (auto i: {1, 2, 3})
std::cout << i << std::endl;
return 0;
}
If your compilation line grows too much you can use the preprocessor (adapted from this answer) as this plain old C code shows:
#if 0
clang "$0" && ./a.out
rm -f ./a.out
exit
#endif
int main() {
return 0;
}
Of course you can cache the executable:
#if 0
EXEC=${0%.*}
test -x "$EXEC" || clang "$0" -o "$EXEC"
exec "$EXEC"
#endif
int main() {
return 0;
}
Now, for the truly eccentric Java developer:
/*/../bin/true
CLASS_NAME=$(basename "${0%.*}")
CLASS_PATH="$(dirname "$0")"
javac "$0" && java -cp "${CLASS_PATH}" ${CLASS_NAME}
rm -f "${CLASS_PATH}/${CLASS_NAME}.class"
exit
*/
class Main {
public static void main(String[] args) {
return;
}
}
D programmers simply put a shebang at the beginning of text file without breaking the syntax:
#!/usr/bin/rdmd
void main(){}
See:
https://unix.stackexchange.com/a/373229/23567
https://stackoverflow.com/a/12296348/199332
For C, you may have a look at tcc, the Tiny C Compiler. Running C code as a script is one of its possible uses.
$ cat /usr/local/bin/runc
#!/bin/bash
sed -n '2,$p' "$#" | gcc -o /tmp/a.out -x c++ - && /tmp/a.out
rm -f /tmp/a.out
$ cat main.c
#!/bin/bash /usr/local/bin/runc
#include <stdio.h>
int main() {
printf("hello world!\n");
return 0;
}
$ ./main.c
hello world!
The sed command takes the .c file and strips off the hash-bang line. 2,$p means print lines 2 to end of file; "$#" expands to the command-line arguments to the runc script, i.e. "main.c".
sed's output is piped to gcc. Passing - to gcc tells it to read from stdin, and when you do that you also have to specify the source language with -x since it has no file name to guess from.
Since the shebang line will be passed to the compiler, and # indicates a preprocessor directive, it will choke on a #!.
What you can do is embed the makefile in the .c file (as discussed in this xkcd thread)
#if 0
make $# -f - <<EOF
all: foo
foo.o:
cc -c -o foo.o -DFOO_C $0
bar.o:
cc -c -o bar.o -DBAR_C $0
foo: foo.o bar.o
cc -o foo foo.o bar.o
EOF
exit;
#endif
#ifdef FOO_C
#include <stdlib.h>
extern void bar();
int main(int argc, char* argv[]) {
bar();
return EXIT_SUCCESS;
}
#endif
#ifdef BAR_C
void bar() {
puts("bar!");
}
#endif
The #if 0 #endif pair surrounding the makefile ensure the preprocessor ignores that section of text, and the EOF marker marks where the make command should stop parsing input.
CINT:
CINT is an interpreter for C and C++
code. It is useful e.g. for situations
where rapid development is more
important than execution time. Using
an interpreter the compile and link
cycle is dramatically reduced
facilitating rapid development. CINT
makes C/C++ programming enjoyable even
for part-time programmers.
You might want to checkout ryanmjacobs/c which was designed for this in mind. It acts as a wrapper around your favorite compiler.
#!/usr/bin/c
#include <stdio.h>
int main(void) {
printf("Hello World!\n");
return 0;
}
The nice thing about using c is that you can choose what compiler you want to use, e.g.
$ export CC=clang
$ export CC=gcc
So you get all of your favorite optimizations too! Beat that tcc -run!
You can also add compiler flags to the shebang, as long as they are terminated with the -- characters:
#!/usr/bin/c -Wall -g -lncurses --
#include <ncurses.h>
int main(void) {
initscr();
/* ... */
return 0;
}
c also uses $CFLAGS and $CPPFLAGS if they are set as well.
#!/usr/bin/env sh
tail -n +$(( $LINENO + 1 )) "$0" | cc -xc - && { ./a.out "$#"; e="$?"; rm ./a.out; exit "$e"; }
#include <stdio.h>
int main(int argc, char const* argv[]) {
printf("Hello world!\n");
return 0;
}
This properly forwards the arguments and the exit code too.
Quite a short proposal would exploit:
The current shell script being the default interpreter for unknown types (without a shebang or a recognizable binary header).
The "#" being a comment in shell and "#if 0" disabling code.
#if 0
F="$(dirname $0)/.$(basename $0).bin"
[ ! -f $F -o $F -ot $0 ] && { c++ "$0" -o "$F" || exit 1 ; }
exec "$F" "$#"
#endif
// Here starts my C++ program :)
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char **argv) {
if (argv[1])
clog << "Hello " << argv[1] << endl;
else
clog << "hello world" << endl;
}
Then you can chmod +x your .cpp files and then ./run.cpp.
You could easily give flags for the compiler.
The binary is cached in the current directory along with the source, and updated when necessary.
The original arguments are passed to the binary: ./run.cpp Hi
It doesn't reuse the a.out, so that you can have multiple binaries in the same folder.
Uses whatever c++ compiler you have in your system.
The binary starts with "." so that it is hidden from the directory listing.
Problems:
What happens on concurrent executions?
Variatn of John Kugelman can be written in this way:
#!/bin/bash
t=`mktemp`
sed '1,/^\/\/code/d' "$0" | g++ -o "$t" -x c++ - && "$t" "$#"
r=$?
rm -f "$t"
exit $r
//code
#include <stdio.h>
int main() {
printf("Hi\n");
return 0;
}
Here's yet another alternative:
#if 0
TMP=$(mktemp -d)
cc -o ${TMP}/a.out ${0} && ${TMP}/a.out ${#:1} ; RV=${?}
rm -rf ${TMP}
exit ${RV}
#endif
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello world\n");
return 0;
}
I know this question is not a recent one, but I decided to throw my answer into the mix anyways.
With Clang and LLVM, there is not any need to write out an intermediate file or call an external helper program/script. (apart from clang/clang++/lli)
You can just pipe the output of clang/clang++ to lli.
#if 0
CXX=clang++
CXXFLAGS="-O2 -Wall -Werror -std=c++17"
CXXARGS="-xc++ -emit-llvm -c -o -"
CXXCMD="$CXX $CXXFLAGS $CXXARGS $0"
LLICMD="lli -force-interpreter -fake-argv0=$0 -"
$CXXCMD | $LLICMD "$#" ; exit $?
#endif
#include <cstdio>
int main (int argc, char **argv) {
printf ("Hello llvm: %d\n", argc);
for (auto i = 0; i < argc; i++) {
printf("%d: %s\n", i, argv[i]);
}
return 3==argc;
}
The above however does not let you use stdin in your c/c++ script.
If bash is your shell, then you can do the following to use stdin:
#if 0
CXX=clang++
CXXFLAGS="-O2 -Wall -Werror -std=c++17"
CXXARGS="-xc++ -emit-llvm -c -o -"
CXXCMD="$CXX $CXXFLAGS $CXXARGS $0"
LLICMD="lli -force-interpreter -fake-argv0=$0"
exec $LLICMD <($CXXCMD) "$#"
#endif
#include <cstdio>
int main (int argc, char **argv) {
printf ("Hello llvm: %d\n", argc);
for (auto i = 0; i < argc; i++) {
printf("%d: %s\n", i, argv[i]);
}
for (int c; EOF != (c=getchar()); putchar(c));
return 3==argc;
}
There are several places that suggest the shebang (#!) should remain but its illegal for the gcc compiler. So several solutions cut it out. In addition it is possible to insert a preprocessor directive that fixes the compiler messages for the case the c code is wrong.
#!/bin/bash
#ifdef 0
xxx=$(mktemp -d)
awk 'BEGIN
{ print "#line 2 \"$0\""; first=1; }
{ if (first) first=0; else print $0 }' $0 |\
g++ -x c++ -o ${xxx} - && ./${xxx} "$#"
rv=$?
\rm ./${xxx}
exit $rv
#endif
#include <iostream>
int main(int argc,char *argv[]) {
std::cout<<"Hello world"<<std::endl;
}
As stated in a previous answer, if you use tcc as your compiler, you can put a shebang #!/usr/bin/tcc -run as the first line of your source file.
However, there is a small problem with that: if you want to compile that same file, gcc will throw an error: invalid preprocessing directive #! (tcc will ignore the shebang and compile just fine).
If you still need to compile with gcc one workaround is to use the tail command to cut off the shebang line from the source file before piping it into gcc:
tail -n+2 helloworld.c | gcc -xc -
Keep in mind that all warnings and/or errors will be off by one line.
You can automate that by creating a bash script that checks whether a file begins with a shebang, something like
if [[ $(head -c2 $1) == '#!' ]]
then
tail -n+2 $1 | gcc -xc -
else
gcc $1
fi
and use that to compile your source instead of directly invoking gcc.
Just wanted to share, thanks to Pedro's explanation on solutions using the #if 0 trick, I have updated my fork on TCC (Sugar C) so that all examples can be called with shebang, finally, with no errors when looking source on the IDE.
Now, code displays beautifully using clangd in VS Code for project sources. Samples first lines look like:
#if 0
/usr/local/bin/sugar `basename $0` $# && exit;
// above is a shebang hack, so you can run: ./args.c <arg 1> <arg 2> <arg N>
#endif
The original intention of this project always has been to use C as if a scripting language using TCC base under the hood, but with a client that prioritizes ram output over file output (without the of -run directive).
You can check out the project at: https://github.com/antonioprates/sugar
I like to use this as the first line at the top of my programs:
For C (technically: gnu C as I've specified it below):
///usr/bin/env ccache gcc -Wall -Wextra -Werror -O3 -std=gnu17 "$0" -o /tmp/a -lm && /tmp/a "$#"; exit
For C++ (technically: gnu++ as I've specified it below):
///usr/bin/env ccache g++ -Wall -Wextra -Werror -O3 -std=gnu++17 "$0" -o /tmp/a -lm && /tmp/a "$#"; exit
ccache helps ensure your compiling is a little more efficient. Install it in Ubuntu with sudo apt update && sudo apt install ccache.
For Go (golang) and some explanations of the lines above, see my other answer here: What's the appropriate Go shebang line?

Complete C++ i18n gettext() "hello world" example

I am looking for a complete i18n gettext() hello world example. I have started a script based upon A tutorial on Native Language Support using GNU gettext by G. Mohanty. I am using Linux and G++.
Code:
cat >hellogt.cxx <<EOF
// hellogt.cxx
#include <libintl.h>
#include <locale.h>
#include <iostream>
#include <cstdlib>
int main (){
char* cwd = getenv("PWD");
std::cout << "getenv(PWD): " << (cwd?cwd:"NULL") << std::endl;
char* l = getenv("LANG");
std::cout << "getenv(LANG): " << (l?l:"NULL") << std::endl;
char* s = setlocale(LC_ALL, "");
std::cout << "setlocale(): " << (s?s:"NULL") << std::endl;
std::cout << "bindtextdomain(): " << bindtextdomain("hellogt", cwd) << std::endl;
std::cout << "textdomain(): " << textdomain( "hellogt") << std::endl;
std::cout << gettext("hello, world!") << std::endl;
}
EOF
g++ -ohellogt hellogt.cxx
xgettext -d hellogt -o hellogt.pot hellogt.cxx
msginit --no-translator -l es_MX -o hellogt_spanish.po -i hellogt.pot
sed --in-place hellogt_spanish.po --expression='/#: /,$ s/""/"hola mundo"/'
sed --in-place hellogt_spanish.po --expression='s/PACKAGE VERSION/hellogt 1.0/'
mkdir -p ./es_MX/LC_MESSAGES
msgfmt -c -v -o ./es_MX/LC_MESSAGES/hellogt.mo hellogt_spanish.po
export LANG=es_MX
ls -l $PWD/es_MX/LC_MESSAGES/hellogt.mo
./hellogt
strace -e trace=open ./hellogt
The program compiles, the text is extracted, Spanish file is created, modified and binary created but hellogt still displays English. The trace shows no evidence of looking in the current working directory for es_MX nor any references to LC_MESSAGES directory.
Your problem is that hellogt.mo is in the wrong location - your program isn't actually opening it. You can tell this by using strace to trace open syscalls:
strace -e trace=open ./hellogt
...
open("/tmp/.//es_MX/LC_MESSAGES/hellogt.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/tmp/.//es/LC_MESSAGES/hellogt.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
You can affect where gettext looks for message catalogs with the LOCPATH environment variable, but if you move it to where gettext is attempting to load it from your example works:
mkdir -p es/LC_MESSAGES
cp hellogt.mo es/LC_MESSAGES
./hellogt
hola mundo
cat >hellogt.cxx <<EOF
// hellogt.cxx
#include <libintl.h>
#include <locale.h>
#include <iostream>
int main (){
setlocale(LC_ALL, "");
bindtextdomain("hellogt", ".");
textdomain( "hellogt");
std::cout << gettext("hello, world!") << std::endl;
}
EOF
g++ -o hellogt hellogt.cxx
xgettext --package-name hellogt --package-version 1.2 --default-domain hellogt --output hellogt.pot hellogt.cxx
msginit --no-translator --locale es_MX --output-file hellogt_spanish.po --input hellogt.pot
sed --in-place hellogt_spanish.po --expression='/"hello, world!"/,/#: / s/""/"hola mundo"/'
mkdir --parents ./es_MX.utf8/LC_MESSAGES
msgfmt --check --verbose --output-file ./es_MX.utf8/LC_MESSAGES/hellogt.mo hellogt_spanish.po
LANGUAGE=es_MX.utf8 ./hellogt
Here is a description of the files created by the above:
hellogt.cxx C++ source file
hellogt Executable image
hellogt.pot Extracted text from C++ source file (portable object template)
hellogt_spanish.po Modified text for Spanish with translations added (using sed)
es_MX.utf8/
LC_MESSAGES/
hellogt.mo Binary translated text for Spanish used at run-time
Here is a description of gettext from Fedora Project. It is simple to follow. But it is in C.
http://fedoraproject.org/wiki/How_to_do_I18N_through_gettext