Linking to a built static library linked to another static library - cmake

Sorry if the title seems a little convoluted. The basic idea is as follows:
I have a main CMakeLists.txt file that adds three subdirectories.
The first of these is a CMakeLists.txt file that pulls a boost-cmake release.
FetchContent_Declare(boost-cmake
GIT_REPOSITORY https://github.com/ *****/boost-cmake
GIT_TAG master)
FetchContent_GetProperties(boost-cmake)
if(NOT boost-cmake_POPULATED)
FetchContent_Populate(boost-cmake)
add_subdirectory(${boost-cmake_SOURCE_DIR} ${boost-cmake_BINARY_DIR})
endif()
The second creates a library linked to this.
add_library(program Program.cpp)
target_link_libraries(program ${Boost_LIBRARIES})
This succeeds and a .lib file is generated. In saying that, it seems to contain symbols for all the boost functions included in Program.cpp #includes
Lastly, when I try to link the program.lib library against an executable:
include_directories(${CMAKE_SOURCE_DIR}/src)
add_executable(program_test Program_Test.cpp)
target_link_libraries(program_test PRIVATE program)
Building this results in the following error:
FAILED: test/CMakeFiles/program_test.dir/program_test.cpp.obj
C:\PROGRA~2\MICROS~1\2019\COMMUN~1\VC\Tools\MSVC\1421~1.277\bin\HostX64\x64\cl.exe /nologo /TP -I..\src /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /ZI /Ob0 /Od /RTC1 /JMC -std:c++latest /showIncludes /Fotest\CMakeFiles\program_test.dir\program_test.cpp.obj /Fdtest\CMakeFiles\program_test.dir\ /FS -c ..\test\program_test.cpp
D:\Git\program\src\connection\program.hpp(5): fatal error C1083: Cannot open include file: 'boost/beast.hpp': No such file or directory
Is it standard to require all nested dependencies like this? Is there possibly any workaround that would instead ensure all of the boost definitions are included within the library thus only requiring the library itself?
Worth mentioning, I have tried including the boost/beast.hpp file in the same way it is included within the library, however this does not seem to solve the problem either, although this would not be a preferable solution regardless.

You don't have a link error, you have a compile error.
D:\Git\program\src\connection\program.hpp(5): fatal error C1083: Cannot open include file: 'boost/beast.hpp': No such file or directory
The VisualStudio compiler can't find boost/beast.hpp. At no point in the CMakeLists.txt that you shared, did you tell your target, program_test, where to find its include files. Just like you added a target_link_libraries() so that the VisualStudio linker can find the libraries, you need to add a target_include_directories() so that the VisualStudio compiler can find the include files in your Program_Test.cpp.

Related

cmake with vcpkg can't find *.lib files

I want to use DirectXTK via vcpkg and link it with my cmake project.
vcpkg.exe list shows the following:
directxtk:x86-windows apr2021 A collection of helper classes for writing Direc...
directxtk:x86-windows-static-md apr2021 A collection of helper classes for writing Direc...
libzip:x86-windows 1.7.3#2 A library for reading, creating, and modifying z...
libzip:x86-windows-static-md 1.7.3#2 A library for reading, creating, and modifying z...
zlib:x86-windows 1.2.11#10 A compression library
zlib:x86-windows-static-md 1.2.11#10 A compression library
[dependnencies from these are not included here]
You can see that DirectXTK,libzip and zlib is installed.
Now my CMakeLists.txt looks like this:
find_package(ZLIB REQUIRED)
target_link_libraries(Game PRIVATE ZLIB::ZLIB)
if(WIN32)
find_package(directxtk CONFIG REQUIRED)
target_link_libraries(Game PRIVATE DirectXTK)
endif()
find_package(libzip REQUIRED)
target_link_libraries(Game PRIVATE libzip)
When I try to compile my project, it says
fatal error LNK1104: cannot open file 'DirectXTK.lib'
fatal error LNK1104: cannot open file 'libzip.lib'
It can't find the lib files for DirectXTK and libzip when linking.
It compiles fine though, which means it can find zlib.h and DirectXTK/WICTextureLoader for example.
How am I supposed to fix that?
The cmake Toolchain is correctly set to vcpkg.cmake and I used vcpkg.exe integrate install prior.

How do I generate PDB files using cmake and gcc?

I want to use the OpenCppCoverage to check the coverage of my source files by my Unit Test. However, it seems that I need to have .pdb files generated for OpenCppCoverage to work.
The problem is that I am not being able to generate such files from my build. Here is my CmakeLists.txt
cmake_minimum_required(VERSION 3.17) # version can be different
project(GUnitTestingVSCode) #name of your project
add_subdirectory(googletest) # add googletest subdirectory
add_compile_definitions(TELEMETRY_DIAGNOSTICS)
add_compile_definitions(GTEST)
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/")
include_directories(googletest/include/) # this is so we can #include <gtest/gtest.h>
include_directories(googletest/googlemock/include/gmock/) # this is so we can #include <gmock/gmock.h>
include_directories("${CMAKE_SOURCE_DIR}/"
"${CMAKE_SOURCE_DIR}/inc/"
"${CMAKE_SOURCE_DIR}/mocks/"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Application"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Datalink/"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Demodulation"
"${CMAKE_SOURCE_DIR}/../submodule/library/inc/Modulation"
"${CMAKE_SOURCE_DIR}/../inc/Peripherals/"
"${CMAKE_SOURCE_DIR}/../inc/Protocol/"
"${CMAKE_SOURCE_DIR}/../inc/Diagnostics/")
file(GLOB_RECURSE SOURCES RELATIVE
${CMAKE_SOURCE_DIR} "../src/Peripherals/DMA.c" "../src/Diagnostics.c"
${CMAKE_SOURCE_DIR} "../src/Protocol/DataLink.c"
"src/*.cpp" "googletest/*.cpp" "mocks/*.c"
"../submodule/library/src/*.c")
add_executable(gUnitTest ${SOURCES}) # add this executable
set(CMAKE_BUILD_TYPE RelWithDebInfo)
set_target_properties(gUnitTest PROPERTIES
COMPILE_PDB_NAME "gUnitTestCompiled"
COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/"
PDB_NAME "gUnitTestLinker"
PDB_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/")
target_link_libraries(gUnitTest PUBLIC gtest gmock) # link google test to this executable
However, when I build my Test folder in RelWithDebInfo mode (I also tried Debug), I get no .pdb files in the build folder. Can someone help me understand what am I doing wrong?
The compiler used is GCC 9.2.0 (mingw32)
I was able to figure out myself. So here is the answer if someone struggles with the same:
gcc compiler is not able to generate .pdb files. What can be done is the following:
Convert the debug information from gcc to pdb files using the converter called cv2pdb
Use llvm/clange compiler that has support to generate .pdb
Use another code coverage tool, such as gcov from gcc itself
I decided to use option 3, and replace opencppcoverage by gcov (in fact I am using gcovr). I had to include the extra flags for coverage as mentioned above:
-fprofile-arcs -ftest-coverage -fPIC -O0

CMake not able to find Debug Library

I am a CMake noob trying to put together a package installer so i can move between my windows development machine and my cluster.
I have the following directory tree for my files (an example)
-Primary
--Library Source
--CMakeLists.txt
--src1.cpp
--src1.h
--Application Source
--CMakeLists.txt
--src1.cpp
--src1.h
--CMakeLists.txt
Each CMakeLists.txt is
Primary/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(BloodVesselRadiationDamageSimulations CXX)
SET(FIND_LIBRARY_USE_LIB64_PATHS true)
SET(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}) #only for testing
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_ROOT}/ ${CMAKE_SOURCE_DIR}/cmake/Modules/")
FIND_PACKAGE(OpenMP)
FIND_PACKAGE(MPI)
FIND_PACKAGE(HDF5)
FIND_PACKAGE(GTest)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
SET(CMAKE_DEBUG_POSTFIX _d)
ADD_SUBDIRECTORY(Source)
ADD_SUBDIRECTORY(SourceUnitTest)
Library Source/CMakeLists.txt
ADD_LIBRARY(VesselProjectBaseLibrary STATIC Src1.cpp
Src1.h)
INSTALL(TARGETS VesselProjectBaseLibrary DESTINATION x64/Debug CONFIGURATIONS Debug)
INSTALL(TARGETS VesselProjectBaseLibrary DESTINATION x64/Release CONFIGURATIONS Release|RelWithDebInfo)
Application Source/CMakeLists.txt
INCLUDE_DIRECTORIES("${GTEST_INCLUDE_DIRS}")
ADD_EXECUTABLE (SourceUnitTests Src1.cpp
Src1.h)
TARGET_LINK_LIBRARIES(SourceUnitTests ${GTEST_LIBRARY})
TARGET_LINK_LIBRARIES(SourceUnitTests debug VesselProjectBaseLibrary_d optimized VesselProjectBaseLibrary)
I am able to generate the projects correctly; I see all the correct files in the projects. However, when i go to compile the debug build I get the following error:
1>ipo: : error #11018: Cannot open VesselProjectBaseLibrary_d.lib
1>LINK : fatal error LNK1104: cannot open file 'VesselProjectBaseLibrary_d.lib'
If i compile my release build everything works perfectly and compilation is successful. The library compiles successfully under both builds.
When you link against a library created within the project, you need to specify library target name, not a library file. CMake will care about proper filename, path and other things:
TARGET_LINK_LIBRARIES(SourceUnitTests VesselProjectBaseLibrary)
Variable CMAKE_DEBUG_POSTFIX affects on library's filename. While file VesselProjectBaseLibrary_d.lib is actually created in debug build, it cannot be found automatically by the linker. Again, use target name and let CMake do all other work.

How to use libxml2 with CMake?

I am using CLion editor (with CMake) for my C project,
I've never used an external library though,
my question is how do I link an external lib (for ex. libxml2) to my project?
I've seen some questions similar to this but none worked for me.
My project is compiled on Windows, and I have libxml .dll, include, and .lib files(binaries for Windows).
Edit: My CMakeLists.txt file after the answer suggested:
cmake_minimum_required(VERSION 3.2)
project(time_table)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES
course.c
course.h
day.h
defines.h
find_tables.c
find_tables.h
item.h
parse_info.c
parse_info.h
table.c
table.h
time_table.c grades.c grades.h)
link_libraries(C:/Users/Gal/Desktop/time_table/libxml2-2.7.8.win32/lib)
add_executable(time_table ${SOURCE_FILES})
target_link_libraries(time_table libxml2)
and this is what I get:
"C:\Program Files (x86)\JetBrains\CLion 1.1.1\bin\cmake\bin\cmake.exe" --build C:\Users\Gal\.clion11\system\cmake\generated\2eda76ff\2eda76ff\Debug --target time_table -- -j 8
[ 14%] Linking C executable time_table.exe
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find -llibxml2
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[3]: *** [time_table.exe] Error 1
CMakeFiles\time_table.dir\build.make:225: recipe for target 'time_table.exe' failed
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/time_table.dir/all' failed
mingw32-make.exe[2]: *** [CMakeFiles/time_table.dir/all] Error 2
CMakeFiles\Makefile2:78: recipe for target 'CMakeFiles/time_table.dir/rule' failed
mingw32-make.exe[1]: *** [CMakeFiles/time_table.dir/rule] Error 2
What is wrong?
There is a key work for libraries installed on your machine. <lib_name>_INCLUDE_DIR and <lib_name>_LIBRARIES once you have done find_package. This works for me.
find_package(LibXml2 REQUIRED)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/<my_stuff> ${LIBXML2_INCLUDE_DIR})
add_executable(<my_exe> <my_source_files>)
target_link_libraries(<my_exe> ${LIBXML2_LIBRARIES})
---- Just a note for your curiosity ----
If you ever needed to build (1) a (static) library of your calculations, maybe reusable, and (2) an executable that uses that library and LIBXML2, do this.
find_package(LibXml2 REQUIRED)
# add a calculation library: file "lib<mycalc>.a"
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/<your header files folder> ${LIBXML2_INCLUDE_DIR})
add_library(<mycalc> STATIC ${CMAKE_CURRENT_SOURCE_DIR}/<your src files folder>)
target_link_libraries(<mycalc> ${LIBXML2_LIBRARIES})
# add the executable: file <my_exe>
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/<your header files folder> ${LIBXML2_INCLUDE_DIR})
add_executable(<my_exe> <your exe src files>)
target_link_libraries(<my_exe> <mycalc> ${LIBXML2_LIBRARIES})
Assume that full path to the library(.lib) can be expressed as
<library_dir>/<library_name>.lib
For compile executable, which uses this library, you need:
CMakeLists.txt:
link_libraries(<library_dir>)
add_excutable(<my_exe> ..)
target_link_libraries(<my_exe> <library_name>)
For use(run) compiled executable, you need to have <library_name>.dll either under one of the directory, listed in the PATH environment variable, or within same directory with executable.
there are 32bit and 64bit version of libxml2, to be found here.
you can put them below the PATH - or the C:\Windows directory.
With moderns CMake (version 3.2 or newer), it got much easier:
Search for the library. CMake has an according find module, thus it boils down to
find_package(LibXml2 REQUIRED)
Then you can link the library it to your target foo
target_link_libraries(foo PUBLIC LibXml2::LibXml2)
That's it folks! No fiddling around with headers and libraries, all done automatically.
If you have not installed the library, you might want to set LibXml2_DIR to the location where LibXml2 is located, i.e., by passing -DLibXml2_DIR=C:\software\libxml2 to your CMake call. That will help CMake finding LibXml2.

CMake adding libraries for Windows/Linux

Visual Studio C++ 2008 / GCC 4.4.2
I have written a program to run on Linux and now I have to port my code to run on Windows. I have decided to use CMake as I want to keep the same build system for both platforms.
However, I need to link with some libraries for both platforms. In my CMakeLists.txt I have the following:
# Compile with gcc c89 standard
IF(CMAKE_COMPILER_IS_GNUCXX)
MESSAGE(STATUS "GCC detected - Adding compiler flags")
SET(CMAKE_C_FLAGS "-pthread -ggdb -Wextra -Wall -pedantic -std=c89")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(WIN32)
SET(CMAKE_C_FLAGS "ws2_32.lib")
ENDIF(WIN32)
However, when I compile on Visual Studio I get the following error:
fatal error C1083: Cannot open source file: 'ws2_32.lib': No such file or directory
What can I do to resolve this problem?
========= Edit
In the top level directory
# Project Client Server
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
# Name of project
PROJECT(CLIENT_SERVER)
# Compile with gcc c89 standard
IF(CMAKE_COMPILER_IS_GNUCXX)
MESSAGE(STATUS "GCC detected - Adding compiler flags")
SET(CMAKE_C_FLAGS "-pthread -ggdb -Wextra -Wall -pedantic -std=c89")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(WIN32)
SET(CMAKE_C_FLAGS "ws2_32")
ENDIF(WIN32)
# Includes
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/cltsvr_ults)
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/server)
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/client)
# libraries
LINK_DIRECTORIES($CLIENT_SERVER/cltsvr_ults)
# Add subdirectories
ADD_SUBDIRECTORY(client)
ADD_SUBDIRECTORY(server)
ADD_SUBDIRECTORY(cltsvr_ults)
ADD_SUBDIRECTORY(test_client)
ADD_SUBDIRECTORY(test_server)
In the subdirectory of client I have this CMakeLists.txt
# libray called client from client.c
ADD_LIBRARY(client client)
And in the subdirectory of test_clt where I create and link my executable.
# Test client add executable
INCLUDE_DIRECTORIES($CLIENT_SERVER_SOURCE_DIR/client)
INCLUDE_DIRECTORIES($CLIENT_SERVER_SOURCE_DIR/cltsvr_ults)
# Link the library
LINK_DIRECTORIES($CLIENT_SERVER/client)
# Add the executable
ADD_EXECUTABLE(clt test_clt)
# Link the executable to the client library
IF(WIN32)
TARGET_LINK_LIBRARIES(clt client ws2_32)
ENDIF(WIN32)
Disclaimer: My answer is of philosophical nature which should encourage you to avoid touching CMAKE_C_FLAGS directly. For the direct answer that just solves your problem look what Bill ( the lead architect of the CMake btw. ) wrote.
The thing about CMake is, that it lets you describe what you want to do without referring to a specific compiler or platform. What CMake does is building the compiler and linker flags from your usage of
include_directories
add_definitions
add_library
add_executable
target_link_libraries
If there are no external dependencies, other than the compiler itself, this is all you need. For external dependencies use
find_package
It defines a set of variables, like
find_package(SDL)
defines
SDL_INCLUDE_DIR
SDL_LIBRARY
for usage with respectively include_directories and target_link_libraries. CMake ships with a bunch of so called module files, like FindSDL.cmake and many others can be googled.
The next lower level is to use
find_path
find_library
which are used in the Find???.cmake modules itself.
The CMAKE_C_FLAGS variable is composed by CMake from these commands. Modifying it means you bypass CMake. There are cases, like for special optimization flags, you want to do this, but at this point all power and thus responsibility transfered from CMake to you.
By adding ws2_32.lib to the C_FLAGS, you are using it at compile time, and not link time. If you look at the error message, you can see it it treating the file as if it were a c++ source file: Cannot open source file: 'ws2_32.lib'. target_link_libraries(target ws2_32) should work.
You need to use the Target Link Libraries command. The target would be the executable you're building.
EDIT: You shouldn't specify the libs you're linking against in C_FLAGS. You can do something like TARGET_LINK_LIBRARIES(execName, ws_32, ...). I'm not 100% sure if you need the .lib. Been a while since I used CMake.