CMake Best Practice for using Targets - boost

I compiled all the information and now iam trying to implement CMake build system for a super project and i really need a guidance here,it would be great to transform all data i acquired by reading about CMake across different sites to practical knowledge
i have a fundamental questions regarding understating CMake Targets
In case of multi directories structure,i want to achieve most portability thus having target for each directory and then use these different targets as link for others in another directories, my goal is to be agile as possible and not be coupled with a certain directory structure, make use of CMake to figure the dependency, where i would be only concerned about targets
my final target is a library of libraries
USE CASE :
First level directory {PROJECT} ( 2 folders ) :
CMakeLists.txt common_env source
​
​First level CMakeLists.txt :
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(dassys)
# iam using this because target scope change with sub-directory
include(common/CMakeLists.txt)
include(src/CMakeLists.txt)
#Add Library
add_library(dassys INTERFACE)
#Creating library
target_link_libraries(dassys INTERFACE
common
src
)
Second Level directory {{PROJECT} /common}(2 folders 1 file ):
cfgd_*** CMakeLists.txt dstdh header.h
Second Level CMakeLists.txt
#Adding Subdirectory
include(${CMAKE_CURRENT_LIST_DIR}/dstdh/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/cfgd_***/CMakeLists.txt)
#add_subdirectory(dstdh)
#add_subdirectory(cfgd_***)
#Add Library
add_library(common INTERFACE)
#Creating library
target_link_libraries(common INTERFACE
dstdh
cfgd_***
)
----------------------------------------------------------------------------------------------------------------------------------
​Thrid Level directory { {PROJECT} /common/dstdh }(6 files ):
CMakeLists.txt dassert.h dfloat.h dstdbit.h dstdbool.h dstdint.h dstdio.h dstring.h
Thrid Level CMakeLists.txt
#Adding Library
add_library(dstdh INTERFACE )
target_sources(dstd INTERFACE
${CMAKE_CURRENT_LIST_DIR}/dassert.h
${CMAKE_CURRENT_LIST_DIR}/dfloat.h
${CMAKE_CURRENT_LIST_DIR}/dstdbit.h
${CMAKE_CURRENT_LIST_DIR}/dstdbool.h
${CMAKE_CURRENT_LIST_DIR}/dstdint.h
${CMAKE_CURRENT_LIST_DIR}/dstdio.h
${CMAKE_CURRENT_LIST_DIR}/dstring.h
)
#Add include for Header only library
target_include_directories(dstdh INTERFACE
"${CMAKE_CURRENT_LIST_DIR}/dstdh/"
)
and here is my question, i need to link against dstd library in another directory
how can this be done because as far as i understand
target_link_libraries ( mylib dstd ) should work in different directory because i have target which is dstd INTERFACE library, and i need Cmake to resolve this dependency by finding this target and link against it
i get compilation error as dstdint.h is not found when mylib is being compiled

Related

CMake: Use variables from existing Makefile of 3rdparty library

I'm facing the following scenario:
Existing project which uses cmake
External 3rdparty library which only comes with Makefiles
The difference of my situation compared to existing questions is that I don't need to have cmake to build the 3rdparty library via the Makefile. Instead, the 3rdparty library provides a library.mk Makefile which has variables like LIB_SRCS and LIB_INCS containing all source and header files required to compile the library.
My idea is to include the library.mk into the project's CMakeLists.txt and then adding those $(LIB_SRCS) and $(LIB_INCS) to target_sources().
My question: How can I include library.mk into the existing CMakeLists.txt to get access to the $(LIB_SRCS) and $(LIB_INCS) for adding them to target_sources()? I'm looking for something like this:
include("/path/to/library.mk") # Somehow include the library's `library.mk` to expose variables to cmake.
add_executable(my_app)
target_sources(
my_app
PRIVATE
main.c
$(LIB_SRCS) # Add 3rd-party library source files
$(LIB_INCS) # Add 3rd-party library header files
)
Using include() does not work as the library.mk is not a CMake list/file.
Since you can't be sure that your target system will even have Make on it, the only option is to parse the strings out of the .mk file, which might be easy if the variables are set directly as a list of filenames, or really hard if they are set with expansions of other variables, conditionals, etc. Do this with FILE(STRINGS) cmake doc.
Your plan will only work if the Makefiles are trivial, and do not set important compiler flags, define preprocessor variables, modify the include directory, etc. And if they really are trivial, skip the parsing, and just do something like aux_source_directory(<dir> <variable>) to collect all the sources from the library directory.
You might also consider building and maintaining a CMakeLists.txt for this third-party library. Do the conversion once, and store it as a branch off of the "vendor" main branch in your version control system. Whenever you update, update the vendor branch from upstream, and merge or rebase your modifications. Or just store it in your existing project, referring to the source directory of the 3rd-party stuff.

Build a Make based C++ project using Android NDK

I need to build csparse library for an Android project. The project supports Make build system.
I am not familiar with use of NDK for Make build. I have used Androids CMake toolchain for building CMake based projects.
I am looking for pointers to usage of NDK for building C++ projects based on Make. I do not want to manually write a CMakeLists.txt for building the project with CMake toolchain because there are too many source files in the csparse project!
Any help is appreciated!
https://developer.android.com/ndk/guides/other_build_systems covers using the NDK with build systems other than ndk-build and CMake. The last section explicitly covers traditional make projects.
OK, It wasn't so difficult. It seems CSparse is a self-contained and does not depend on other linear-algebra libraries such as CHOLMOD, BLAS, LAPACK, Metis... etc
Here is the CMakeLists.txt file from my Android project :
cmake_minimum_required(VERSION 3.4.1)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include/CSparse/Source
)
add_library( # Sets the name of the library.
csparse-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
include/CSparse/Source/cs_add.c
include/CSparse/Source/cs_amd.c
include/CSparse/Source/cs_chol.c
include/CSparse/Source/cs_cholsol.c
include/CSparse/Source/cs_compress.c
include/CSparse/Source/cs_counts.c
include/CSparse/Source/cs_cumsum.c
include/CSparse/Source/cs_dfs.c
include/CSparse/Source/cs_dmperm.c
include/CSparse/Source/cs_droptol.c
include/CSparse/Source/cs_dropzeros.c
include/CSparse/Source/cs_dupl.c
include/CSparse/Source/cs_entry.c
include/CSparse/Source/cs_ereach.c
include/CSparse/Source/cs_etree.c
include/CSparse/Source/cs_fkeep.c
include/CSparse/Source/cs_gaxpy.c
include/CSparse/Source/cs_happly.c
include/CSparse/Source/cs_house.c
include/CSparse/Source/cs_ipvec.c
include/CSparse/Source/cs_leaf.c
include/CSparse/Source/cs_load.c
include/CSparse/Source/cs_lsolve.c
include/CSparse/Source/cs_ltsolve.c
include/CSparse/Source/cs_lu.c
include/CSparse/Source/cs_lusol.c
include/CSparse/Source/cs_malloc.c
include/CSparse/Source/cs_maxtrans.c
include/CSparse/Source/cs_multiply.c
include/CSparse/Source/cs_norm.c
include/CSparse/Source/cs_permute.c
include/CSparse/Source/cs_pinv.c
include/CSparse/Source/cs_post.c
include/CSparse/Source/cs_print.c
include/CSparse/Source/cs_pvec.c
include/CSparse/Source/cs_qr.c
include/CSparse/Source/cs_qrsol.c
include/CSparse/Source/cs_randperm.c
include/CSparse/Source/cs_reach.c
include/CSparse/Source/cs_scatter.c
include/CSparse/Source/cs_scc.c
include/CSparse/Source/cs_schol.c
include/CSparse/Source/cs_spsolve.c
include/CSparse/Source/cs_sqr.c
include/CSparse/Source/cs_symperm.c
include/CSparse/Source/cs_tdfs.c
include/CSparse/Source/cs_transpose.c
include/CSparse/Source/cs_updown.c
include/CSparse/Source/cs_usolve.c
include/CSparse/Source/cs_util.c
include/CSparse/Source/cs_utsolve.c
)
add_library(native-lib SHARED native-lib.cpp)
find_library( # Sets the name of the path variable.
log-lib
log)
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
csparse-lib
)
I hope this answer helps others.

Necessity of include_directories command in cmake project

I'm following a tutorial on CMake and I have problems understanding the necessity of using the 'include_directories' command at one point.
Let me explain the project first:
In my working directory I have:
- a main.cpp function, a CMakeLists.txt(the main one), a configuration file, a 'MathFunction' directory and a 'build' directory
In the MathFunction directory I have:
- a CMakeLists.txt file that will be invoked by the main one
- A file 'mysqrt.cxx' that contains the implementation of a function which will be used in 'main.cpp' application
- A 'MathFunctions.h' header file that contains the prototype of that function
In the CMakeLists from 'MathFunction' directory I'm creating a library using code from 'mysqrt.cxx' like this:
add_library(MathFunctions mysqrt.cxx)
This snippet is a part of my main CMake code:
# add the MathFunctions library?
#
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") # WHY DO WE NEED THIS
add_subdirectory (MathFunctions)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
add_executable(Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)
Now I do not understand why I need too add that 'include_directories' command in order to use the library? Shouldn't it be enough that the last command 'target_link_libraries' links the already created executable and libraries togheter so there would be no need to also include_directories?
Thank you for reading and I'm sorry if I have not explained it very well but I hope you will understand what I mean :D
Command include_directories sets directories for header files (.h) to be searched. Linking (target_link_libraries) with a library basically specifies only a library file (.so, .dll or other type). As you see, these are different things.
When linking executable with a library target, CMake propagates (more precisely, "consumes") some properties of that library target to the executable. Among these properties there is INTERFACE_INCLUDE_DIRECTORIES property, which adds include directories to the executable.
So, when a library target has INTERFACE_INCLUDE_DIRECTORIES property correctly being set, you don't need to explicitly specify include directories for executable:
MathFunctions/CMakeLists.txt:
add_library(MathFunctions mysqrt.cxx)
# Among other things, this call sets INTERFACE_INCLUDE_DIRECTORIES property.
target_include_directories(MathFunctions PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
CMakeLsits.txt:
add_executable(Tutorial tutorial.cxx)
# This also propagates include directories from the library to executable
target_link_libraries (Tutorial MathFunctions)
Note, that using simple
# This *doesn't* set INTERFACE_INCLUDE_DIRECTORIES property.
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
in MathFunctions/CMakeLists.txt doesn't imply propagating include directories to the linked executable.

Visual Studio Solution Style using CMakelists [duplicate]

I have a CMake project that looks like this:
project/
CMakeLists.txt
subprojectA/
CMakeLists.txt
include/
headerA.hpp
src/
libraryA.cpp
subprojectB/
CMakeLists.txt
src/
mainB.cpp
The "library" subproject, A, is compiled as a static library, becoming libsubprojectA.a. The "main" project, B, is compiled as a binary and depends on the library. mainB.cpp includes a reference to headerA.hpp.
Here is subprojectA/CMakeLists.txt:
project(SubProjectA)
include_directories(include)
add_library(subprojectA STATIC src/libraryA.cpp)
set(${PROJECT_NAME}_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/include
CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
And here is subprojectB/CMakeLists.txt:
project(SubProjectB)
include_directories(${SubProjectA_INCLUDE_DIRS})
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
The main Project CMakeLists.txt looks like:
project(Project)
add_subdirectory(subprojectB)
add_subdirectory(subprojectA)
Note that subprojectB, the main project, is listed before subprojectA.
Here's the problem. When I first run "cmake" on this project, ${SubProjectA_INCLUDE_DIRS} is not set within SubProjectB.
What I think is happening is that the CMakeLists for SubProjectB loads first, when ${SubProjectA_INCLUDE_DIRS} has not yet been set. It sets its own include path to an empty string as a result. However, even though libsubprojectA.a gets built successfully before mainBinary, the include path was already set empty beforehand. As a result, I get this error when trying to make mainBinary:
subprojectB/src/mainB.cpp:1:23: fatal error: headerA.hpp: No such file or directory
#include "headerA.hpp"
^
It's a workaround to put subprojectA before subprojectB in the main Project CMakeLists in the declarative world of CMake. What I really want is to know the proper way to indicate to CMake that the include_directories(${SubProjectA_INCLUDE_DIRS}) line depends on the definitions that exist inside SubProjectA's CMakeLists. Is there a better way to do this?
If you want to express that include directory subprojectA/include is an interface of the library subprojectA, attach this property to the target with target_include_directories command:
subprojectA/CMakeLists.txt:
project(SubProjectA)
add_library(subprojectA STATIC src/libraryA.cpp)
# PUBLIC adds both:
# 1) include directories for compile library and
# 2) include directories for library's interface
target_include_directories(subprojectA PUBLIC include)
So any executable(or other library) which linked with subprojectA will have this include directory automatically:
subprojectB/CMakeLists.txt:
project(SubProjectB)
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
Of course, for use last command properly you need to process directory with library before one with executable:
CMakeLists.txt:
project(Project)
add_subdirectory(subprojectA)
add_subdirectory(subprojectB)

CMake Hierarchical Project Management Without Abusing Libraries

I have a project where there's only a handful of logical groupings for generating static libraries. However for convenience I want to have the library's source code to be managed with more granular folders.
Currently the only way I know to do this in CMake without having a library for each folder is to just list files as you would normally in with their relative paths:
add_library(SystemAbstraction STATIC "Some/Path/File.cpp")
However I can see this getting unwieldy as the project grows in size with all the different paths.
I tried to see if I could have a CMakeLists.txt in each folder and just use a variable in the base CMakeLists.txt when adding library dependencies. But it seems that add_subdirectory doesn't also import variables?
For expanding the scope of a variable inside a subdirectory, use the PARENT_SCOPE option of set. For example, you can test that if you have
# CMakeLists.txt
set(SRCS main.c)
add_subdirectory(foo)
message(${SRCS})
in the root directory and
# foo/CMakeLists.txt
set(SRCS ${SRCS} foo.c PARENT_SCOPE)
in a subdirectory then it will print main.c foo.c, i.e., the variable is correctly imported into the base CMakeLists.txt.
An option would be to use the object library feature of CMake. You still can but doesn't need to organise your CMake script into subdirectories:
add_library(lib1 OBJECT <srcs>)
add_library(lib2 OBJECT <srcs>)
...
add_library(mainlib $<TARGET_OBJECTS:lib1> $<TARGET_OBJECTS:lib2>)
You can set different compile flags for each object library:
target_include_directories(lib1 PRIVATE incl-dir-for-lib1)
target_compile_definitions(lib2 PRIVATE def-for-lib2)
You still need to set link libraries on your main library:
target_link_libraries(mainlib PRIVATE deps-of-lib1 deps-of-lib2)
Related documentation: Object Libraries

Resources