CMake: Override libraries added by target_link_libraries - c++

So I am running into a pretty large headache building my software with CMake.
I am building a third party library statically (dlib) which requires zlib and libpng (both also static, I prebuilt these) libraries to support PNG functionality. The CMakeFile provided by the COTS dlib library is doing a basic:
target_link_libraries( dlib ${dlib_required_libs})
This is making all of its libraries configured as "general" libraries, which end up being used for both Release and Debug builds.
This isn't an issue in Linux, but Windows has a lovely "feature" of specifying the runtime library (/MT or /MD or /MTd or /MDd). Any mismatches between these flags cause multiple symbol definition errors at link time. i.e. If libpng was built with /MT and my software is using /MTd, they will be incompatible.
To alleviate this, I have two built versions of zlib and libpng. One set using the /MT flag for Release builds and the other /MTd for Debug builds. These happily link into my own software using optimized/debug flags on target_link_libraries where they are used. HOWEVER, dlib (3rd party) is only linking the Release set of the zlib and libpng libs by the way it's CMakeFile has been written.
My main question is, is there a way I can 'override' what dlib is linking without modifying it's provided CMakeFile?
I attempted overwriting dlib_LIB_DEPENDS and forcing it into the cache out of desperation, to no avail.

FindPNG.cmake script, like many other Find*.cmake scripts used by find_package(), does not care about multiconfig builds. So it just searched single library, while multiconfig builds naturally want library-per-config.
For make searched PNG library to be per-config, one can to write own FindPNG.cmake script (and set CMAKE_MODULE_PATH to point to the directory with this script).
But for concrete usage it is simpler to just rewrite output of the original script, that is set PNG_LIBRARY cache variable pointed to library-per-config:
optimized png-lib-release debug png-lib-debug
or, using generator expressions,
$<$<CONFIG:Release>:png-lib-release>$<$<CONFIG:Debug>:png-lib-debug>`
(instead of png-lib-release and png-lib-debug should be paths to the release and debug version of the library conrrespondingly).
Both these values are expected to be used with target_link_libraries command,
producing per-config linkage.

Dlib comes with copies of libpng and zlib in dlib/external. By default, dlib's CMakeLists.txt will build them the correct way and statically link them into your program. So the solution is to let it do that. Don't try to create a separate static library because, as you noted, that causes a lot of trouble on windows.

Related

Custom build cmake using standard library also for project with lower gcc version

I have a custom build cmake v3.10.0 which was compiled with a gcc_4.8.3. I am using this custom build cmake to compile a cmake project that must use gcc _4.1.2 because of legacy code.
Executing cmake promted me with an error because it needs to use the libstdc++-IFX.so.6 provided by gcc_4.8.3 which I fixed by adding the path to the correct library in my LD_LIBRARY_PATH before the path to the libraries provided by gcc_4.1.2.
Compiling my project and linking an executable (which is done by c++) results in the linker taking the gcc_4.8.3 stdlibs over the gcc_4.1.2 libs. Is there any way to tell cmake to not use the libraries it needs for himself for my cmake project preferably without touching LD_LIBRARY_PATH?
Edits:
#squareskittles comment: I did read and try everything this post suggest but without any changes. The libstdc++-IFX.so.6 is still taken from gcc_4.8.3

What can linking to a CMake target impact?

I ran into an interesting problem today. I am trying to compile and link a test executable to the Boost unit test framework and I tried it in two different ways.
The classic approach of linking directly to the "boost_unit_test_framework" library using -lboost_unit_test_framework
The modern CMake approach of linking to the Boost::unit_test_framework CMake target.
Interestingly when I link to the library directly my code compiles and links fine; however when I link to the CMake target my code fails to compile before it even gets to the linking stage!
The errors I get are related to a header file that it suddenly can't seem to find anymore. This suggests that linking to the Boost::unit_test_framework somehow messed with my include path.
I know linking to a CMake target is supposed to be the more modern and preferred approach, but if it can have such unexpected and unexplainable side effects, it seems worse than just linking straight to the library...
Why would linking the CMake target cause header files to not be found anymore? Also what other kinds of things can linking to a CMake target instead of linking directly to a library impact?
In both scenarios I am using target_link_libraries to link to the boost library. For example
target_link_libraries(mytest_exe
testlib
-lboost_unit_test_framework
)
or
target_link_libraries(mytest_exe
testlib
Boost::unit_test_framework
)
The fact that it is failing before linking means that the target_link_libraries command in CMake actually effects more than just linking. It is effecting the compilation as well.
Yes, it is true that new include directories are added when you link with a library target instead of the library file. This is why the approach is called "modern" - a single target_link_libraries call does all things which are needed to use the library (Boost in your case).
Reason of failing with "modern" approach could be that "true" Boost headers conflict with other headers you use. You may detect that via inspecting chain of include files in the error message.

Visual C++ executable will not run without Boost DLLs

I'm using Visual Studio to compile a C++ project using CMake as the build system.
Furthermore I'm linking against the Boost library. The output executable however will not run if the following Boost DLLs are not found in the PATH environment variable: boost_filesystem-vc141-mt-x64-1_69.dll and boost_iostreams-vc141-mt-x64-1_69.dll.
According to the documentation, I tried using the /MT ("Causes the application to use the multithread, static version of the run-time library") and also the /MD ("Causes the application to use the multithread-specific and DLL-specific version of the run-time library") compilation flag but besides affecting the file size, the DLL dependence on Boost did not change.
I also specified the following CMake variables:
set(BOOST_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
This did not force static linking against the Boost libraries either. I want to generate an executable which does not dynamically depend on Boost but only on the core C++ runtime libraries so any other machine can run it without shipping Boost or any Boost DLLs. It is totally fine if the file size increases quite a bit.
Adding the following preprocessor define to main.cpp does not work either:
#define BOOST_ALL_NO_LIB 1
How can I really build the standalone executable?
So it turns out that I just misspelled setting Boost to use the static libraries:
set(Boost_USE_STATIC_LIBS ON)
CMake variables are case-sensitive so spelling out Boost with capital letters does not work.
The precompiled Windows binaries already contain everything needed so compiling yourself is not necessary if you just want to link against the static libraries.

Using google protobuf with libraries in cmake on Windows, Visual Studio 2013

I have a CMake project with several sub-directories and library modules that eventually get built into client and server libraries, and those libraries are used from executable to test them. I am trying to use Google's protobuf library inside one of those libraries. I am creating my sub-library as follows:
include_directories(
.
../rendering_backend
../shared
${MY_THIRDPARTY_DIR}/protobuf/include
)
add_library(Client STATIC
client.cpp
client.hpp
../common.hpp
../shared/protobufs/my_bufs.pb.cc
../shared/protobufs/my_bufs.pb.h
)
target_link_libraries(Client
RenderingBackend
${MY_THIRDPARTY_DIR}/protobuf/lib/libprotobufd.lib
)
The executable is declared as follows:
add_executable(TEST_Client
client_tester.cpp
../src/rendering_backend/rendering_backend.hpp)
target_link_libraries(TEST_Client Client)
All these files seem to be generating properly, but when I build, I get the following error (and many just like it):
libprotobufd.lib(zero_copy_stream_impl.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug' in client_tester.obj
I have gone back to the protobuf solution and verified that all projects are set to use /MDd in their Runtime Library setting. It was generated following the guide at https://github.com/google/protobuf/tree/master/cmake.
I have seen many questions and answers about protobufs, but none seem to address this problem. I don't know what could be trying to build /MTd when everything is set to /MDd inside Visual Studio.
Assuming that this process would work if I were doing it correctly, I can only assume I'm doing something wrong. What is the intended way to do something like this?
[EDIT]
I was trying to use protobuf 3.0.0 here.
In order for find_package to identify the correct paths, you must edit the CMAKE_PREFIX_PATH variable to search for libraries. This code allows it to find the path correctly, assuming that you have correctly set up THIRDPARTY_DIR and you downloaded the release version of protobuf (2.6.1 as of this writing):
set(CMAKE_PREFIX_PATH
${CMAKE_PREFIX_PATH}
${THIRDPARTY_DIR}/protobuf-2.6.1
)
Protobuf3 can also be used but in addition to setting the install path in CMAKE_PREFIX_PATH, you must also supply the CONFIG argument to find_package as follows:
find_package(Protobuf CONFIG REQUIRED)
...assuming Protobuf is required.
In my case, I configured Protobuf 3.0.0 beta 2 to install to a folder "install" within its own directory:
set(CMAKE_PREFIX_PATH
${CMAKE_PREFIX_PATH}
${THIRDPARTY_DIR}/protobuf-3.0.0-beta-2/install
)
find_package(Protobuf CONFIG REQUIRED)
(Thanks to tamas.kenez for correcting me on this.)
Note that I had to build the release library before find_package(Protobuf) would return without errors. I originally only build the debug libraries.
I also had to be cautious of which MSVC runtime I build with. Dynamic seems to be the default for most projects, but Protobuf3 builds with the static runtime unless you configure it to do otherwise (there's a checkbox if you're using the GUI). Linking static runtime libraries to dynamic runtime executables causes all kinds of linker problems and redefinitions, so be careful of that.
Lastly, CMake GUI seems to retain some information about directory structures until you reload the project (or possibly restart the program entirely); so I hit a snag in trying to change which version of protobuf I used when CMake kept finding a directory structure I had already deleted, even after clearing the whole build directory. (Solved by clearing the build directory and relaunching CMake GUI and reloading the base project.)
You can use git-subtree or git-submodule to make google protobuf sources part of your solution and build it with your project.
Add to your top-level CMakeLists.txt
add_subdirectory("third-party/protobuf/cmake")
include_directories("third-party/protobuf/src")
to get all protobuf targets.
Then you can add dependency to protobuf with
target_link_libraries(YourLibrary libprotobuf libprotobuf-lite libprotoc)
Hope this helps.

How to deploy boost library?

I have used Boost library (particularly, Boost filesystem) for my project in Visual Studio C++ (9.0 version). This Boost library is installed in C drive. My project is already finished, therefore, I have corresponding Debug and Release.
Now, I want to include particular DLLs of Boost filesystem to Debug and Release, so my first question is which DLLs do I need to copy? It shows many DLLs for filesystem. Ones which I tried are "boost_filesystem-vc90-mt-1_40.dll" and "boost_filesystem-vc90-mt-gd-1_40.dll". Since, I got an idea from the "vc90", I think it means for Visual Studio 9.0?
Second question, even if I don't include these Boost filesystem DLLs to Debug or Release, my EXE file of the project is still working? Can anyone please explain why is this happening? I tried to check if I have Boost Library path somehow in my Environment Variables, but, unfortunately I could not find them there. Thanks a lot.
P.S.: I am a beginner in both C++ and Boost. And, another library that I am using is OpenCV, for which I already copied corresponding DLLs (core, highgui and imgproc) to Debug and Release and this one is working perfectly.
You have 2 options:
a. Deploy Boost DLLs together with your binary. Answering your question - of course if your project depends on Boost, the libraries are required at runtime, your binary will not start without them.
If you deploy Release configuration of your project, then you need boost_filesystem-vc90-mt-1_40.dll library. In general you can just see all the dependencies of your binary using Dependency Walker tool.
b. Link Boost libraries statically, in this case your binary will not have runtime dependency on Boost DLLs, so you don't have to deploy them