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.
Related
I have a VisualStudio-2019 C++ Project which uses CMake and Ninja to build a dll, the Project uses functions from a few Libraries like protobuf and spdlog, which I have installed using vcpkg.
When building, the output gets written to four distinct dll files and all of them are needed for the main-dll to run.
Below are two screenshots: left the current state and right the expected state.
The main.dll file should include all the functions it imports, the compiler shouldn't create separate dlls for each library.
I don't know knob I need to turn, I can imagine several ways to edit:
The C++ Code of the Project (Classes, inlining functions ?)
The CMakeList.txt
The Arguments of MSVC (compiler, linker flags)
The Arguments of Ninja
Where should I start ?
Setting the mentioned flags or appending -static to the import library components had no effect, I went as far as
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "-static")
set(CMAKE_MODULE_LINKER_FLAGS "-static")
set(CMAKE_SHARED_LINKER_FLAGS "-static")
set(CMAKE_STATIC_LINKER_FLAGS "-static")
But this didn't help a bit.
As it turned out this is a problem with vcpkg:
I had installed the packages with the triplet x64-windows, which builds for dynamic linkage, installing the packages with
vcpkg install --triplet=x64-windows-static protobuf spdlog makes static linking possible. If the static variants are not installed, the build proceeds silently with the dynamic ones.
Lately, I have been using cmake as a generator for my projects. I have successfully generated many vtk and other application projects. However, I now face a problem when trying to link both dynamic and static precompiled libraries. In particular, I have been given some dynamic precompiled third party dlls along with their respective .lib files. Furthermore, I am trying to link some static precompiled libraries (only .lib files) to my project so as to check the software licences.
Let say that my project is called test_example and I have some precompiled dynamic libraries in libs directory. The structure of my project directory is:
Test_example
-/include
-/libs
-/build
-CMakeLists.txt
The CMakeLists.txt for linking the dynamic libaries has the following content:
cmake_minimum_required(VERSION 2.8.9)
project (test_example)
set(CMAKE_BUILD_TYPE Release)
#For the shared libraries:
set (PROJECT_LINK_LIBS dynamic_1.dll dynamic_2.dll )
set (PROJECT_LINK_DIR ${test_example_SOURCE_DIR}/libs/)
set (PROJECT_INCLUDE_DIR ${test_example_SOURCE_DIR}/include/)
link_directories(${PROJECT_LINK_DIR})
include_directories(${PROJECT_INCLUDE_DIR})
add_executable(test_example test_example.cpp)
target_link_libraries(test_example ${PROJECT_LINK_LIBS})
When I generate the project with this cmake lists, I can successfully use methods from the precompiled dlls. However, I have not found a way to link against my static libraries, as well. Let say I have one static library which is called test_licence.lib. Should I drop it in the libs folder as well and simply refer to it like I do with the dynamic? When I do so and when opening my project solution in Visual Studio, I can see that both dynamic and static libraries have been added to Linker-->Input-->Additional DEpendencies. However, when I am trying to build the project, I have unresolved external dependencies which are methods from the static lib.
Does any of you have any idea what would be the most efficient way to accomplish that? Many thanks in advance!
There is a couple of issues here.
Unlike to what you may be used to from VS, CMake prefers absolute paths for linking, instead of setting a link directory and giving the relative path.
Also, you do not link against .dll files. Dlls are loaded at runtime, not at link time. Many dlls are shipped with import libraries (with a .lib ending), that handle the runtime loading automatically for you. These are the ones you should link against.
Also try not to hardcode libraries in CMake code. The problem here is that if something goes wrong, you end up with a cryptic linker error. You should use find_library instead, which will usually make CMake complain early if something is off.
A cleaner version of your CMake script would be something like
cmake_minimum_required(VERSION 2.8.9)
project (test_example)
# note setting the build type does nothing on a visual studio build
# and should probably be left to the user for other generators
set(CMAKE_BUILD_TYPE Release)
#For the shared libraries:
# this call will succeed if it finds a dynamic_1.lib file
find_library(DYNAMIC_LIB1 dynamic_1 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT DYNAMIC_LIB1)
message(FATAL_ERROR "Library dynamic_1 was not found!")
endif()
find_library(DYNAMIC_LIB2 dynamic_2 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT DYNAMIC_LIB2)
message(FATAL_ERROR "Library dynamic_2 was not found!")
endif()
# for the static libraries:
# basically the same; again this looks for a static_1.lib file
find_library(STATIC_LIB1 static1 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT STATIC_LIB1)
message(FATAL_ERROR "Library static_1 was not found!")
endif()
set (PROJECT_INCLUDE_DIR ${test_example_SOURCE_DIR}/include/)
include_directories(${PROJECT_INCLUDE_DIR})
add_executable(test_example test_example.cpp)
target_link_libraries(test_example ${DYNAMIC_LIB1} ${DYNAMIC_LIB2} ${STATIC_LIB1})
Double check in Visual Studio that all libraries were added as linker inputs, as expected. If you still get linker errors, it means that something is wrong with your third-party .lib file. Open a new question with the exact linker error that you get.
Here is how we are doing it:
Firstly, use add_library with final arguments STATIC IMPORTED. Then subsequently use set_property to set the IMPORTED_LOCATION property, which is a path to the built library. For example, we pull in gtest like so:
add_library(gtest UNKNOWN IMPORTED)
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/gtest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest.a)
Then, gtest is a known library in your build system and you can link with it normally later on by just doing
target_link_libraries(target-name gtest)
See also: Cmake imported libraries documenation
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.
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.
Using a bunch of different libraries in my project (from GitHub sources, not precompiled), I add them to my target like this in my root CMakeLists.txt file:
add_subdirectory(lib/glew-1.13.0/build/cmake)
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/lib/glew-1.13.0/include/)
...
target_link_libraries(MyApp glew ${GLEW_LIBRARIES} ... )
However, you can see from the screenshot below that Xcode includes all of the sources for those libraries in my project, which makes an insanely long list that I have to scroll through to find my code.
I have tried the EXCLUDE_FROM_ALL flag in the add_subdirectory command, which removes the library sources from my Xcode project, but then I cannot compile my project because Xcode doesn't compile the library at all.
Additionally, Xcode gives me tons of warnings from the libraries that I don't really care about. Using the SYSTEM flag with the include_directories command doesn't fix it.
What's the best way to solve this? Should I be compiling my libraries as a completely separate part of my build process rather than compiling them with my executable?
I'm not sure how it will work, but try this:
turn on the USE_FOLDERS in your root CMakeLists.txt
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
And then after you've added all the projects, set the FOLDER target property on all of the third party libraries:
set_property(TARGET target1 target2 ...
PROPERTY FOLDER "ThirdPartyLibs")
Being unfamiliar with C++, I thought that all of my libraries should be compiled along with my project every time. I ended up solving this by writing a shell script that precompiles all of my libraries once as static libraries, and now I don't have to worry about their sources in my IDE, plus I get faster compile times.