CMake link stage question - c++

I am currently building a rather large application, using cmake to generate cross platform build scripts. During this process of putting together the cmake build scripts, I have discovered the pain of gcc link line ordering.
The basic issues is that including static libraries in the wrong order leads to unused library symbols being thrown away that then cannot be found by subsequent dependent libraries.
Thus, I am in the situation where cmake generates a visual studios build system that compiles just fine, but the unix makefiles throw all kinds of "undefined symbol" errors. I have figured out a work around for this - in the add_executable command, I am including the static libraries twice.
My hope is that there is a more standard/better way to deal with this issue. Being that I am not the only developer, and that the majority of regular development is done in windows, I really want a link-order agnostic CMake script. The windows developers just don't deal with this link order issue. On top of that, figuring out the correct order would be very difficult - I do not have that information readily available and there are a lot of static libraries (70 or so).
After searching the internet, I did learn about the -static and -dynamic flags, but getting CMake to include them is non-obvious and gcc complains about not being able to find the dynamic libraries.
Anyway, I welcome suggestions on how to do the right thing.

Did you try disabling the strip? Maybe with something like cmake -DCMAKE_STRIP=/bin/true ..? Maybe that will stop the symbols being thrown out.

I think this is less of a CMake issue, and more of a GCC behavior. This question/answer should help out a bit:
Linker order in GCC
You will have to bite the bullet and modify your CMakeLists.txt files to link properly on Linux. Since the Windows developers don't care, you shouldn't disturb them.
Best,
-dan

Related

MSVC Find where a symbol is coming from

Situation:
I am using CI to compile a Windows version of my project using CMake and MSVC
It errors out right at the end complaining of two missing symbols (__std_system_error_allocate_message and __std_system_error_deallocate_message)
When I replicate the build process on my own computer, the build finishes fine and the artifacts run without errors.
Searching for these symbols on Google yields no clues as to which libraries they are supposed to be defined in.
Which leads to my question:
Is it possible to see where the MSVC linker is finding a particular symbol?
I was able to find instructions to look at what symbols are defined in a particular library, but this project is linking dozens of libraries, and the ones I have searched so far do not define the symbol. I think this approach is prone to errors as I might miss a library without knowing it.
#Richard Critten pointed me on the right path, the problem was due to having different versions of the MSVC toolchain on each system. GitLab's CI runners were using build tools version 16.2.3.0 while I was using a more recent 16.6.1.0. Uninstalling that and installing 16.2.3 from this page reproduced the error. Recompiling a dependency I had previously compiled with the newer toolchain then resolved the error on both systems.

C++ - How to make a program compiled with MinGW standalone?

I am working on a project(for Windows) that is small and should be portable. I saw somewhere that MinGW gets rid of the requirement of some .dlls on the target system, so I thought I'd give it a try. To my suprise, when I tried running my program on a friend's computer, I got two errors saying that 2 different .dlls were missing. I thought MinGW used the system dlls, but it obviously didn't work. I saw an article on how to make a standalone exe with Visual Studio, but I'd prefer to use MinGW due to it's simplicity.
So my question: How to produce a standalone exe with MinGW?
Note: I am only using standard libraries, but it'd be nice to know how to include other libraries for future projects.
If you'd like an example of what I mean by a standalone exe, putty is a good example(it is an ssh client for Windows).
The two libraries you needed were most likely libgcc_s_sjlj-1.dll and libstdc++-6.dll or some variation of these, depending on how your mingw was configured when it was built. These are C and C++ standard library implementations.
If you want, you can pass extra flags to the compiler when you are linking the final executable, -static-libgcc and -static-libstdc++, which will cause it to link these libraries in statically instead of requiring you to distribute DLLs for them with your executable.
More info here: Mingw libgcc_s_sjlj-1.dll is missing
In general you can always try to statically link libraries into your executable. These special -static-libgcc flags are special flags provided only by mingw, not by other compilers, and not for other libraries, you use a different -static syntax for other libs. Static linking is fine but it gets more complicated and error prone as the dependencies get more complex. Static linking has some pitfalls associated to the order in which the libraries are linked. After a certain point, its usually simpler to make them all shared and don't do any static linking. It's up to you, it depends on how complex your project gets / if you start to have problems.

Only relink shared libraries when headers change in CMake

Using CMake, is there a way to generate build systems that don't relink everything downstream if a shared library's source code changes without its headers changing?
In Makefiles, I've used rules with an order only prerequisite on the shared library itself and regular prerequisites on the library headers to get this effect.
I know this isn't strictly guaranteed to produce a correct build, e.g. you could delete a function definition from the shared library, but this is for quickly rebuilding a debug build and in my experience it almost always has produced a correct build. I think there was once or twice that I ran into a runtime linker error but on that odd occasion it's not much trouble to run the build as usual.
Still, if there are good reasons that this is actually a terrible idea and shouldn't be done that could be an answer too.
In CMake 2.8.11 and later you can set CMAKE_LINK_DEPENDS_NO_SHARED to get this behavior.
http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/43246/focus=44469
http://www.cmake.org/cmake/help/v3.1/prop_tgt/LINK_DEPENDS_NO_SHARED.html

Executable runtime crash caused by linking with dynamic library

Stack: MIPS, Linux, C, C++ using GNU Tools to compile and link (building on x86 for MIPS)
Fair warning: I'm a C, C++ novice, feel free to suggest anything which might be obvious as it's possible I have not tried it yet.
I am able to build an executable which dynamically links to a library (live555), if I statically link to this everything works fine, however when I attempt to dynamically link the executable crashes during runtime. To confirm I am building the .so files correctly, I've also tried building other executables (the test tools included with live555) to dynamically link against these .so libs and these tools work fine.
The linking/build seems to work fine, no errors or warnings are thrown during the build. I can inspect the crashing executable with readelf -d and clearly see the .so references. I can also run ldd on the MIPS system on the executable and the libraries seem to be loaded fine, strace output also shows these libraries as being loaded. Unfortunately the strace output doesn't really provide me with any insite, I've talked with others familiar with this system and they are not sure what the problem is.
Just looking for ideas and tools to try, if anyone has any thoughts I'd appropriate them!
Thanks for reading
There is not enough information here to start troubleshooting in depth. Some ideas to start debugging, from least to most time-consuming:
After you run ldd on your executable, check the path(s) where that library is being loaded from, make sure the library is the version you compiled / linked against. Easy way is to get it's MD5 hash on your target and host, make sure they are the same.
Also check to make sure you don't have multiple instances of the library installed
Double check the aliases for your library, make sure they point to the same place
Try enabling crash dump generation $> ulimit -c unlimited, run gdb or DDD, load the crash dump and inspect your environment.
Check your CFLAGS, it could be as #YannRamin said, you need -fPIC for MIPS. You can run make -n to see how your binary is being generated.
Check your LDPATH env on target and make sure it is sensible; empty is perfectly fine btw.
Check your LDFLAGS during compile / linking. You might have to run make -n, look for gcc command or collect command, then copy-paste the entire line and add --verbose to the end so you can see exactly what the linker is doing. You might have to fix paths for sources / object files, depending on how your build system is setup.
The idea is to try and eliminate potential issues, such as:
wrong library version: installed vs compiled against
multiple locations / bad aliasing
symbol pollution when compiling / linking
many others
You're lucky that you have Linux installed, so should be fairly easy, just might be time consuming.

Using 3rd Party Libraries in C++

I'm totally spinning my wheels with getting a couple of 3rd party libraries to work with my c++ programs. I'm looking for some general advice (40,000 foot level) about the general steps that one needs to take when implementing libraries.
First, some specifics: I am using code::blocks in Windows as my IDE. I like this IDE and really don't want to switch to anything else if I don't have to (I've tried visual c++ and also some things in linux). The libraries that I am trying to use are GMP and crypto++.
OK. What I think I know is this: After downloading the library, I unzip the file to a folder. I've been unzipping directly to C:\ with each zip file extracted to its own folder (e.g. c:\cryptopp and c:\gmp). I think that the next step is to build the library, but this is where I get totally stuck. How is this done? There are no executable files among those extracted. From what I can tell, I believe that I do this in code::blocks, but I have no idea how?
Finally, assuming that I can get this done, which I believe creates the .lib files, the last step before actually using the library in my code, is to link into the library. This part, I believe that I understand.
So, my question is broad: do I understand this process overall? And if so, how do I go about building these libraries, if in fact that it the thing that I am missing.
Thanks very much for indulging my ignorance. I'm totally rudderless right now and despite hours and hours on google, I'm making no progress. Also, feel free to correct anything that I have stated as fact that is not correct. Thanks a lot!
Usually libraries have a special file called makefile in them, and are built with a utility called Make (or one of it's variations, whatever works uder windows).
Usually all you have to do is to run Make in the directory where you have unpacked the source files, and it will do the rest itself.
If those libraries you mention (GMP and crypto++; disclaimer: I'm not familiar with either of them) don't have project files for code::blocks then you may still be able to compile them under Windows with MinGW.
If you have installed MinGW you use the MinGW shell to navigate to the appropriate directories which would be /c/cryptopp/ and /c/gmp in your examples - The MinGW shell works like a Unix shell, and has different naming conventions.
Then you need to compile the libraries. Check whether there's a Makefile in those directories, if there isn't you can check whether there's a configure script, which will generate the Makefile. If you have the Makefile you can type make which will compile the libraries with MinGW's port of the GCC compiler.
When the compilation is complete you should have a library in the form of a .a file (say libcryptopp.a) that you can link to your project. In code::blocks you would set the linker path (the -L command line option in GCC) to C:\cryptopp\bin or wherever the library has been compiled, and then add libcryptopp.a to the list of libraries you want to link (this is associated with the -l option in GCC). The convention is to leave out the lib prefix and the .a extension, so you would just add cryptopp to your library list. In the end your linker options should look like -LC:\cryptopp\bin -lcryptopp along with the
Also, to be able to use the libraries you need to add the path to the headers directory to the include path of your project. This is associated to the -I command line option in GCC, so your compiler's command line options would have something like -IC:\cryptopp\include somewhere.
Of course, all of the above assumes that you use code::blocks with GCC. If you're using it with VisualC++ then the principles are the same, but the specific steps differ.