environment A: centos7(same os) / gcc.7.3.1(higher gcc)
environment B: centos7(same os) / gcc.4.8.5(lower gcc)
I have built an C++ executable in environment A and run it in environment B.
I haven't had a problem so far, but could there be a problem with this approach?
Technically, building a static executable improves portability.
So compile your C++ files with g++ -O -Wall -Wextra -g and link the object files with g++ -static *.o
Alternatively, use dynamically only libc.so, not the C++ standard library. So link with g++ *.o -Bstatic your libraries -Bdynamic -lc
For details, read the documentation of GCC, of GNU binutils, perhaps of GNU bash, and the Program Library Howto and Drepper's paper How to write shared libraries
Notice that to run an executable (see elf(5) and execve(2) and other syscalls(2)....) you don't need a compiler.
You may want to use strace(1) and ldd(1) on machine B.
Don't forget to have many testcases.
Notice that GCC, Bash, Binutils, are free software. You are allowed to download and study their source code and improve it (there are licensing conditions when you redistribute an improved binary, read their GPL license)
You could have legal or licensing issues (e.g. if your C++ code uses Qt). You may need to consult a lawyer about them.
See also LinuxFromScratch.
Related
I am writing some OpenGL code, and my links to libraries in /usr/lib is getting quite unwieldly:
g++ Application.cpp -lglfw -lGL -lGLEW
I don't want to hunt around/can't remember the exact names of the libraries EVERY TIME i want to complile something, so in my project folder I have a file called linkingsNeeded.txt. That file contains that command and nothing else. Is there a way to save the list of linkings so I can just type
g++ Application.cpp
And not have to deal with manually linking? Say, in the #include section of the CPP file?
Learn to use some build automation tool such as GNU make or ninja.
You'll then edit your Makefile (with make); this could be inspirational and just build your program by typing make. Most source code editors (like GNU emacs) or IDEs can be easily configured to run make with a single keypress.
Of course you want to invoke GCC as g++ -Wall -Wextra -g since you want all warnings and debug info (for the GDB debugger).
Read also How to debug small programs and more about C++, perhaps even the n3337 quasi C++11 standard.
I have wrapped my C++ header file in an extern "C" block to allow calling C++ functions from C. I have included the proper header files in the proper places. It works if I do something like the following:
g++ -c cpp_src.cc
gcc -c c_src.c
gcc -o c_exe c_src.o cpp_src.o -lstdc++
But if I remove the -lstdc++ from the last line, I get a bunch of errors. Because of reasons beyond my control, I cannot add the -lstdc++ flag. Is there a way to get the above to work without -lstdc++? What exactly is lstdc++, as in how does the gcc use it while linking with g++ compiled code?
Also, cpp_src.cc uses STL, if that makes a difference.
If you really need to have an object file that you can link with gcc without using -lstdc++, you can do an incremental link of your C++ object file with -lstdc++ and then use the result of that on your gcc link line. Something like:
ld -i -static cpp_src.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -lstdc++ -o cpp_withstdlib.o
This will link your C++ object file with the standard C++ library and produce a new object file (cpp_withstdlib.o) that contains all the standard C++ library stuff you need, so can be linked on the gcc command line without needing -lstdc++
The tricky part is the -L option -- you need to figure out where g++ has stashed its standard library, as it generally doesn't put it in the standard /usr/lib location. The above is for an Ubuntu 14.04 machine. On most Linux machines, you can find it with locate libstdc++.a
You're generally just better off using g++ to link C++ code, as it knows all the right paths and won't make little mistakes that result in a binary that superficially appears to work, but is actually incorrect.
Using Josh's suggestion, you can do:
ld -i -static cpp_src.o `g++ -print-file-name=libstdc++.a` -o cpp_withstdlib.o
which is a bit cleaner, and could readily be done in a Makefile.
-lstdc++ causes the linker to link to libstdc++, which is gcc's implementation of the C++ standard library. If your code uses any symbols from the standard library (it uses the standard library, and not all code is inlined from headers), it must link libstdc++ (or whichever standard library implementation you use).
You can avoid the standard library, or you can link against the system standard library, or you can statically link a copy of the standard library into your program.
My requirement is to work on some interface .h files. Right now I have .h and .cpp/.cc files in my project.
I need to compile it into shared 64-bit linux compatible library (*.so), using NetBeans/ Eclipse on Linux Fedora.
Since the GCC C++ ABI conventions did slightly change (in particular because of C++ standard libraries evolution, or name mangling convention) from one GCC version to the next (e.g. from g++-4.4 to g++-4.6) your shared library may be dependent upon the version of g++ used to build it
(In practice, the changes are often small inside g++, so you might be non affected)
If you want a symbol to be publicly accessible with dlsym you should preferably declare it extern "C" in your header files (otherwise you should mangle its name).
Regarding how to make a shared library, read documentation like Program Library Howto.
See also this question
And I suggest building your shared libraries with ordinary command-line tools (eg Makefile-s). Don't depend upon a complex IDE like NetBeans/ Eclipse to build them (they are invoking command-line utilities anyway).
If you are compiling a library from the 3 C++ source files called a.cc, b.cc, and c.cc respectively;
g++ -fpic -Wall -c a.cc
g++ -fpic -Wall -c b.cc
g++ -fpic -Wall -c c.cc
g++ -shared -Wl,-soname,libmylib.so.0 -o libmylib.so.0.0.0 a.o b.o c.o
Then you install the library using ldconfig, see man 8 ldconfig
you can then compile the program that uses the libary as follows (but be sure to prefix extern "C" before the class declarations in the header files included in the source code using the library.)
g++ -o myprog main.cc -lmylib
I have tried these compile options with my own sample code, and have been successful.
Basically What is covered in Shared Libraries applies to C++, just replace gcc with g++.
The theory behind all of this is;
Libraries are loaded dynamically when the program is first loaded, as can be confirmed by doing a system call trace on a running program, e.g. strace -o trace.txt ls which will dump a list of the system calls that the program made during execution into a file called trace.txt. At the top of the file you will see that the program (in this case ls) had indeed mmapped all the library's into memory.
Since libraries are loaded dynamically, it is unknown at link time where the library code will exist in the program's virtual address space during run time. Therefore library code must be compiled using position independent code - Hence the -fpic option which tells the translation stage to generate assembly code that has been coded with position independent code in mind. If you tell gcc/g++ to stop after the translation stage, with the -S (upper case S) option, and then look at resulting '.s' file, once with the -fpic option, and once without, you will see the difference (i.e. the dynamic code has #GOTPCREL and #PLT, at least on x86_64).
The linker, of course must be told to link all the ELF relocatatable object types into executable code suitable for use as a Linux shared library.
Being perfectly satisfied with old-style Makefiles, I am looking for a simple alternative to libtool. I do not want to switch to automake, and I keep running into problems with libtool when I try to use it directly. The latest one is 'unsupported hardcode properties', and I am getting fed up with the lack of complete documentation that just tells me what is wrong this time...
I only want to compile a bunch of .o files with the right flags and then link them into a shared library, such that it works on as many platforms as possible. Is there anything out there that does just that and not force me to switch all of my other tools at the same time?
I not sure if it would fit info your workflow but I'd recommend looking at CMake. It works on Windows, Linux and Mac and should not force you to change any of your other tools. You'll have to judge its suitability yourself though.
There's jlibtool (which has nothing to do with java).
It's written in C, and can just be bundled with your source.
It was originally an apache project, but whoever was working it there seems to of abandoned it around 2004.
It was taken over by FreeRADIUS project maintainer Alan Dekok, who modernised the code and fixed a few niggling issues. We use it for the FreeRADIUS project (>= 3.0.0) to do all the build time linking.
Given your description in the comment to Milliams' answer,
I just want one tool that I tell: "give me the compiler flags so that I can compile these n files for use in a shared library, and then give me the commands to link them together",
then libtool may well be the simplest tool for the job. I know of no other alternative.
You are right that the documentation for using libtool with plain makefiles is practically nonexistent, but libtool certainly does not require you to switch to automake. Cross-platform libraries are difficult, and the price you have to pay for them is libtool. (Or maybe the discount price is libtool+automake+autoconf or CMake or Jam.)
slibtool (dl.midipix.org/slibtool, git://midipix.org/slibtool) is a libtool drop-in replacement, written in C. A single slibtool binary aims to seamlessly support both native and cross-builds, and the utility also provides some additional features (installation of .la files is optional, optional color-coded annotation, etc). The following minimal plain makefile demonstrates how to (cross-) build a library using slibtool.
CC = cc
LIBTOOL = slibtool
DESTDIR = destdir
all: libfoo.la
a.lo:
$(LIBTOOL) --mode=compile --tag=CC $(CC) -c a.c
libfoo.la: a.lo
$(LIBTOOL) --mode=link --tag=CC $(CC) -o libfoo.la -rpath /lib
install: all
mkdir -p destdir
$(LIBTOOL) --mode=install cp libfoo.la $(DESTDIR)
# the -rpath argument is required for semantic compatibility with libtool.
native build, default (both shared library and static library)
$ make
$ make install
native build, shared library only
$ make LIBTOOL=slibtool-shared
$ make install
native build, static library only
$ make LIBTOOL=slibtool-static
$ make install
cross-build, default
$ make CC=some-target-tuple-gcc
$ make install
cross-build, default, with lots of colors
$ make LIBTOOL=dlibtool CC=some-target-tuple-gcc
$ make install
I have a brand-new off-the-cd OSX 10.6 installation.
I'd now like to compile the following trivial C program as a 64bit binary:
#include <stdio.h>
int main()
{
printf("hello world");
return 0;
}
I invoke gcc as follows:
gcc -m64 hello.c
However, this fails with the following error:
Undefined symbols:
"___gxx_personality_v0", referenced from:
_main in ccUAOnse.o
CIE in ccUAOnse.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
What's going on here? Why is gcc dying?
Compiling without the -m64 flag works fine.
Two things:
I don't think you actually used gcc -m64 hello.c. The error you got is usually the result of doing something like gcc -m64 hello.cc- using the C compiler to compile C++ code.
shell% gcc -m64 hello.c
shell% ./a.out
hello world [added missing newline]
shell% cp hello.c hello.cc
shell% gcc -m64 hello.cc
Undefined symbols:
"___gxx_personality_v0", referenced from:
_main in ccYaNq32.o
CIE in ccYaNq32.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
You can "get this to work" with the following:
shell% gcc -m64 hello.cc -lstdc++
shell% ./a.out
hello world
Second, -m64 is not the preferred way of specifying that you'd like to generate 64-bit code on Mac OS X. The preferred way is to use -arch ARCH, where ARCH is one of ppc, ppc64, i386, or x86_64. There may be more (or less) architectures available depending on how your tools are set up (i.e., iPhone ARM, ppc64 deprecated, etc). Also, on 10.6, gcc defaults to -arch x86_64, or generating 64-bit code by default.
Using this style, it's possible to have the compiler create "fat binaries" automatically- you can use -arch multiple times. For example, to create a "Universal Binary":
shell% gcc -arch x86_64 -arch i386 -arch ppc hello.c
shell% file a.out
a.out: Mach-O universal binary with 3 architectures
a.out (for architecture x86_64): Mach-O 64-bit executable x86_64
a.out (for architecture i386): Mach-O executable i386
a.out (for architecture ppc7400): Mach-O executable ppc
EDIT: The following was added to answer the OPs question "I did make a mistake and call my file .cc instead of .c. I'm still confused about why this should matter?"
Well... that's a sort of complicated answer. I'll give a brief explanation, but I'll ask that you have a little faith that "there's actually a good reason."
It's fair to say that "compiling a program" is a fairly complicated process. For both historical and practical reasons, when you execute gcc -m64 hello.cc, it's actually broken up in to several discrete steps behind the scenes. These steps, each of which usually feeds the result of each step to the next step, are approximately:
Run the C Pre-Processor, cpp, on the source code that is being compiled. This step is responsible for performing all the #include statements, various #define macro expansions, and other "pre-processing" stuff.
Run the C compiler proper on the C Pre-Processed results. The output of this step is a .s file, or the result of the C code compiled to assembly language.
Run the as assembler on the .s source. This assembles the assembly language in to a .o object file.
Run the ld linker on the .o file(s) to link the various compiled object files and various static and dynamically linked libraries in to a useable executable.
Note: This is a "typical" flow for most compilers. An individual implementation of a compiler doesn't have to follow the above steps. Some compilers combine multiple steps in to one for performance reasons. Modern versions of gcc, for example, don't use a separate cpp pass. The tcc compiler, on the other hand, performs all the above steps in one pass, using no additional external tools or intermediate steps.
In the above, traditional compiler tool chain flow, the cc (or, in our case, gcc) command is called a "compiler driver". It's a "logical front end" to all of the above tools and steps and knows how to intelligently apply all the steps and tools (like the assembler and linker) in order to create a final executable. In order to do this, though, it usually needs to know "the kind of" file it is dealing with. You can't really feed an assembled .o file to the C compiler, for example. Therefore, there are a couple of "standard" .* designations used to specify the "kind" of file (see man gcc for more info):
.c, .h C source code and C header files.
.m Objective-C source code.
.cc, .cp, .cpp, .cxx, .c++ C++ Source code.
.hh C++ header file.
.mm, .M Objective-C++ source code.
.s Assembly language source code.
.o Assembled object code.
.a ar archive or static library.
.dylib Dynamic shared library.
It's also possible to over-ride this "automatically determined file type" using various compiler flags (see man gcc for how to do this), but it's generally MUCH easier to just stick with the standard conventions so that everything "just works" automatically.
And, in a round about way, if you had used the C++ "compiler driver", or g++, in your original example, you wouldn't have encountered this problem:
shell% g++ -m64 hello.cc
shell% ./a.out
hello world
The reason for this is gcc essentially says "Use C rules when driving the tool chain" and g++ says "Use C++ rules when driving the tool chain". g++ knows that to create a working executable, it needs to pass -lstdc++ to the linker stage, whereas gcc obviously doesn't think this is necessary even though it knew to use the C++ compiler at the "Compile the source code" stage because of the .cc file ending.
Some of the other C/C++ compilers available to you on Mac OS X 10.6 by default: gcc-4.0, gcc-4.2, g++-4.0, g++-4.2, llvm-gcc, llvm-g++, llvm-gcc-4.0, llvm-g++-4.0, llvm-gcc-4.2, llvm-g++-4.2, clang. These tools (usually) swap out the first two steps in the tool chain flow and use the same lower-level tools like the assembler and linker. The llvm- compilers use the gcc front end to parse the C code and turn it in to an intermediate representation, and then use the llvm tools to transform that intermediate representation in to code. Since the llvm tools use a "low-level virtual machine" as its near-final output, it allows for a richer set of optimization strategies, the most notable being that it can perform optimizations across different, already compiled .o files. This is typically called link time optimization. clang is a completely new C compiler that also targets the llvm tools as its output, allowing for the same kinds of optimizations.
So, there you go. The not so short explanation of why gcc -m64 hello.cc failed for you. :)
EDIT: One more thing...
It's a common "compiler driver technique" to have commands like gcc and g++ sym-link to the same "all-in-one" compiler driver executable. Then, at run time, the compiler driver checks the path and file name that was used to create the process and dynamically switch rules based on whether that file name ends with gcc or g++ (or equivalent). This allows the developer of the compiler to re-use the bulk of the front end code and then just change the handful of differences required between the two.
I don't know why this happens (works fine for me), but
Try compile with g++, or link to libstdc++. ___gxx_personality_v0 is a symbol used by GNU C++ to set up the SjLj callback for the destructors, so for some reason C++ code creeps into your C code. or
Remove the -m64 flag. Binaries generated by GCC 4.2 on 10.6 defaults to 64-bit as far as I know. You can check by file the output and ensure it reads "Mach-O 64-bit executable x86_64". or
Reinstall the latest Xcode from http://developer.apple.com/technology/xcode.html.
OK:
adding -m64 doesn't do anything, a normal gcc with no options is a 64-bit compile
if you are really just off-the-cd then you should update and install a new xcode
your program works fine for me with or without -m64 on 10.6.2
We had a similar issue when working with CocoaPods when creating and using a pod that contained Objective-C++ code so I thought it's also worth mentioning:
You should edit the .podspec of the pod that contains the c++ code, and add a line like:
s.xcconfig = {
'OTHER_LDFLAGS' => '$(inherited) -lstdc++',
}