How to build a static library from two directories? - c++

I have two folders with two different libraries.
LibBase
LibPublic
LibB includes some LibBase's headers.
I'd like to have LibPublic as a static library including "LibBase" in its .a file.
Each CMakeLists.txt is:
set(SRCLIB file.cpp)
add_library(${PROJECT_NAME} ${SRCLIB})
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_include_directories(...)
The top level CMakeLists.txt:
add_subdirectory(LibBase)
add_subdirectory(LibPublic)
How can I force CMake to include LibBase inside LibPublic so that I can only share libLibPublic.a?
LibBase is a proprietary library and LibPublic is the "public" library we share.
LibBase and LibPublic, both may be added using add_subdirectory() by other libraries or apps so that a single app executable or a single .a file can be provided. Each "library" should be compiled as just objects, static library or even dynamic library. I'd like them to be generic, and an upper CMakeLists.txt will decide what to do.
I tried with add_library(${PROJECT_NAME}-obj OBJECT ${SRCLIB}) but I get errors:
CMakeLists.txt:22 (target_include_directories):
Cannot specify include directories for target "LibPublic" which is not
built by this project.

Given the following file and some dummy cpp files:
cmake_minimum_required(VERSION 3.10)
project(foo)
add_library(Base STATIC base.cpp)
add_library(Public STATIC public.cpp)
target_sources(Public PRIVATE $<TARGET_OBJECTS:Base>)
I end up with a libPublic.a that contains functions from both libraries.
Note that this is a solution to your question, but maybe not a solution to your underlying requirement: static libraries are simple collections of functions and the functions in "Base" are plainly visible.

Related

Cmake Top level project has two dependent projects, one child is also dependent on the other child

I have Project A at the top.
Project A requires library B and library C.
Library B also requires library C by itself.
So, in short. How can I link libraries B and C up to A by just linking B?
I have it working now by individually linking all the libraries, but I feel like there is redundancy I could get rid of.
This is part of the CMAKE for Project A at the top:
find_package(libB REQUIRED)
include_directories(${libB_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libB_LIBRARY})
find_package(libC REQUIRED)
include_directories(${libC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libC_LIBRARY})
But also within libB I have this in its CMAKE:
find_package(libC REQUIRED)
include_directories(${libC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libC_LIBRARY})
I feel like there is a better way to do this, please let me know. Thank you for any help.
You can use target_include_directories (documentation) to specify include directories for your target instead of specifying them for all targets of the current directory using include_directories. Among other things, this gives the ability to provide visibility specifiers to your includes dirs, which control whether your include dirs will affect only current target (PRIVATE), only those targets which link to your target (INTERFACE) or both (PUBLIC). The same specifiers are used similarly for target_link_libraries.
So, you can use PUBLIC to avoid duplicating your lib C includes and libraries, and since it is the default specifier, you can omit it. Then, parts of your CMakeLists may look like this:
In project A CMakeLists.txt:
find_package(libB REQUIRED)
target_include_directories(${PROJECT_NAME} ${libB_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libB_LIBRARY})
In lib B CMakeLists.txt:
find_package(libC REQUIRED)
target_include_directories(${PROJECT_NAME} ${libC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libC_LIBRARY})
If you, e.g., want only lib B to link to lib C, but leave public 'inheritance' of include directories, you could change the last line of lib B CMakeLists.txt excerpt:
target_link_libraries(${PROJECT_NAME} PRIVATE ${libC_LIBRARY})

CMake imported library include_directories before other ones

I have a cmake project with an IMPORTED library which has a include directory which must be used before the include directories of the executable.
I tried the following:
cmake_minimum_required(VERSION 3.20)
project(test_cmake)
set(CMAKE_CXX_STANDARD 98)
#Librarry
add_library(lib SHARED IMPORTED)
target_include_directories(lib SYSTEM BEFORE INTERFACE ./lib_inc/)
set_target_properties(lib PROPERTIES IMPORTED_IMPLIB "lib.lib")
add_executable(test_cmake main.cpp)
target_include_directories(test_cmake AFTER PRIVATE include)
target_link_libraries(test_cmake PRIVATE lib)
But at least with the generator "Visual Studio 9 2008" the directory "include" in used before "lib_inc". Does anybody know a way to modify the imported lib so that there include will be the first?
Does anybody know a way to modify the imported lib so that there include will be the first?
The answer is no. Compiler command lines are computed by walking the DAG of linked libraries and placing the merged interface properties in (de-duplicated) pre-order starting with the "top" target. So there is no interface property that can do exactly what you want.
I have a [...] library which has a include directory which must be used before the include directories of the executable.
Frankly, this is a really dubious requirement. The library cannot know to which executables it will be linked so it cannot be a requirement to override its linkers' (as in "linker" and "linkee", not ld) include paths. Similarly, if this library L were a dependency of a static library S, and an executable E linked to S, what should happen with the "before" include dirs of L? Should they override E's? If so, that would be a truly confusing behavior, whereby no target can ever trust its own headers to be used, ever.
So this is not only not available, it's pretty dubious that it ever should be available. This just isn't a coherent semantics for property propagation.

cmake/cpack distribute a library and its dependencies

Let's say I have to distribute a C++ library libA which depends on other libraries libB and libC.
The final user will have to include just the header files of libA but needs to link also the others two.
What's the preferable way to distribute all together the libraries?
Is it possible to use cpack to take care of it?
If you have to hide the source code, then you could precompile the libraries yourselves and just distribute the static .a files and the header files seperately for each distribution.
However, If you want the code to be transparent to the end users and let the users compile the libraries on their own. Then you could try cmake.
The common folder structure for a library will look like this
MainFolder
src ( To have all the required Src files )
include ( all the necessary files to be included )
test ( to run test cases upon installation to validate a successfull installation -- optional )
Then you could create a CMakeLists.txt file in the root folder which would look like this,
cmake_minimum_required(VERSION 3.2)
project(MyAwesomeLibrary)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")// Sets up the compiler and flags
include_directories("${CMAKE_SOURCE_DIR}/include") // This includes the .h files in include directory
// Set the Codes to be compiled for Different Libraries
set (LIB_A ${CMAKE_SOURCE_DIR}/lib_a.c);
set (LIB_B ${CMAKE_SOURCE_DIR}/lib_b.c);
set (LIB_C ${CMAKE_SOURCE_DIR}/lib_c.c);
add_library(MyAwesomeStaticLib STATIC ${LIB_A} ${LIB_B} ${LIB_C}) // Generates the static library
If you have multiple files to be compiled for each of the libraries then you can refer this link.
how would I compile multiple files in a folder?
Then the end user can use the library by linking the generated MyAwesomeStaticLib.a file and also use the -I flag to include the include directories.

stop cmake target_link_libraries linking both object files of static lib in addtion to the static lib itself

I've tried to build a rather large shared library on Windows with cmake + ninja + msvc, that is composed of multiple static libs from subfolders. So a root CMakeLists.txt looks like:
project (sharedlib CXX)
include(${CMAKE_CURRENT_LIST_DIR}/staticlib1/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/staticlib2/CMakeLists.txt)
add_library(sharedlib SHARED)
target_link_libraries(sharedlib
staticlib1
staticlib2
)
set_target_properties(wux PROPERTIES LINK_FLAGS "/WHOLEARCHIVE")
Where the CMakeLists.txt in sub-folders staticlib1 and staticlib2 both look something like:
add_library(staticlib1 STATIC)
target_sources(staticlib1 PUBLIC
${CMAKE_CURRENT_LIST_DIR}/sourceA.cpp
${CMAKE_CURRENT_LIST_DIR}/sourceB.cpp
)
target_include_directories(staticlib1 PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
target_compile_options(staticlib1 PUBLIC
/flag1
/flag2
)
When I run cmake --build both staticlib1 and staticlib2 get built no problem. Cool. But when the linker tries to build sharedlib, the cmake-generated rsp file has:
CMakeFiles\sharedlib.dir\staticlib1\sourceA.cpp.obj
CMakeFiles\sharedlib.dir\staticlib1\sourceB.cpp.obj
CMakeFiles\sharedlib.dir\staticlib2\sourceC.cpp.obj
CMakeFiles\sharedlib.dir\staticlib2\sourceD.cpp.obj
staticlib1.lib
staticlib2.lib
So I get linker errors because symbols are defined twice. How do I get cmake to stop adding both the objects and the final libs to the linker rsp?
Technically I don't need the static libs after the fact. However, I cannot simply switch to using OBJECT libraries. The actual project has ~250 static libs, comprising ~3500 object files. The linker dies (out of memory) with just a fraction of the object files.
I must build up the static libs first and then link just them into the shared lib after the fact, to get around the memory limitations of the linker. Our current build scripts follow this pattern just fine, so I know it works. I just need cmake to follow the same pattern.
This is the effect of target_sources command: with PUBLIC keyword it adds sources both for the library (static) and for anyone who links that library.
You should instead use PRIVATE keyword, or, better, add sources in the add_library call itself:
add_library(staticlib1 STATIC
${CMAKE_CURRENT_LIST_DIR}/sourceA.cpp
${CMAKE_CURRENT_LIST_DIR}/sourceB.cpp
)

CmakeList: Dependencies for static libraries

Let's imagine we have two static libraries which are separate projects:
################################################
# Logger library ###############################
set(Logger_INCLUDE_DIRS Logger/include)
set(Logger_LIBRARIES Logger)
add_library(Logger STATIC
${PROJECT_HEADERS}
${PROJECT_RESOURCES}
${PROJECT_SOURCES}
${MISC}
)
target_include_directories(Logger
PUBLIC
include
)
################################################
# Utils library ################################
add_library(Utils STATIC
${PROJECT_HEADERS}
${PROJECT_RESOURCES}
${PROJECT_SOURCES}
${MISC}
)
Utils library depends on Logger library for logging
Which of these ways will be right to provide Logger sources for Utils library or they are both incorrect and I need to use another one
I have two options here, first one is to provide only *.h file, as far as understood it is enough for static library:
target_include_directories(Utils
PUBLIC
include
${Logger_INCLUDE_DIRS}
)
The other one is to use target_link_libraries, as far as I understood *.h files are linked too but in general we do not need to link one static library with another one and this is redundant:
target_link_libraries(Utils
${Logger_LIBRARIES}
)
Use target_link_libraries whenever one library/executable target uses another library target. Do not think about redudancy of linking static libraries.
In CMake, linking targets is much more than simple linking libraries. Large part of CMake is propagating libraries properties when linking. Just use that.
Also, if you will decide to transform your STATIC library into SHARED, using target_link_libraries provide no additional actions in such transformation.