Link one project to another CMAKE - cmake

I am building a project which contains lots of sub projects. for example as ...
LibA (build as shared library)
LibB (depends on LibA & build as shared library)
AppB (depends on LinB)
Directory structure (Which I want) is as ...
bin/
output/
src/libA/
src/libB/
src/appB/
Each of sub projects (LibA, LibB & AppB) has their own CMakeLists.txt file.
I want ..
1. Build LibA as shared library (I know how to do it)
2. Build LibB as shared library with linking of LibA (Don't Know how to do)
Explanation: When I start building LibB,
LibA build first and
ready to link for LibB
when LibB ready to finish
3. Build AppB : If I start building AppB,
LibA build first and
LibB build after and
both linked to AppB
Now I know classic way, build separately LibA & LibB and supplied path of lib and include to AppB. But I want to build them at once like
Build LibA
Build LibB (if LibA is already build then ignore, else build LibA)
Build AppB (if LibA, LibB are already build then ignore, else build them)
What I want
How can I achieve such behavior using CMAKE ?
It should be cross platform
Simple enough to include many more sub projects

Here is one solution. You can use a top-level CMakeLists.txt file to tie all the projects together. So in your directory structure, this would be placed here:
bin/
output/
src/libA/
src/libB/
src/appB/
CMakeLists.txt <--- Top-level CMakeLists.txt
Your top-level CMakeLists.txt file (as a sibling to the src directory) could look like this:
cmake_minimum_required(VERSION 3.11)
# Add your dependencies in the order you want them to build.
add_subdirectory(src/libA)
add_subdirectory(src/libB)
add_subdirectory(src/appB)
With each of the src directories having their own CMakeLists.txt file, here's an example of each of these individually.
You can set up LibA as a shared library with CMake with the CMakeLists.txt file in src/libA:
project(LibA_Project)
add_library(LibA SHARED sourceA.cpp ... more sources here ...)
Next, CMake will traverse to the src/libB directory to configure LibB. Here is what the src/libB/CMakeLists.txt file could look like:
project(LibB_Project)
# Create a shared library for LibB as well.
add_library(LibB SHARED sourceB.cpp ... more sources here ...)
# Link LibA to LibB as a dependency.
target_link_libraries(LibB LibA)
Finally, CMake will go to the src/appB directory. Here is that CMakeLists.txt file:
project(AppB_Project)
# Create the executable AppB.
add_executable(AppB main.cpp ... more sources here ...)
# Link LibA and LibB to AppB as dependencies.
target_link_libraries(AppB LibA LibB)
This approach can easily be expanded to include more sub-projects (e.g. LibC, LibD, AppE, etc) if necessary.

Related

CMake relative path Libraries communication

Lets say that we have a directory which also has two libraries inside like :
/Example
-/libA:
CMakeLists.txt
source1.c
-/libB:
source2.c
source2.h
Is there any way, without having an external CMakeLists.txt file from libA and libB, to exists access from the source1.c file in libA in source2 files from libB?
All am I need is if i could with some way build the CMakeLists.txt in libA with a way in order, when I build my project not showing the error, cant find files from libB.
I was trying this but it faild.
add_library(libA STATIC source1.c)
add_library(libB STATIC source2.c source2.h)
target_link_libraries(libA PUBLIC libB)

How to include static libraries in a static library?

I have 2 static libraries in two different folders: libA and libB
libB must include libA
My main CMakeLists.txt is:
add_subdirectory(libA)
add_subdirectory(libB)
My first mistake was to think linking libA in libB would include it but it isn't:
target_link_libraries(${PROJECT_NAME} PUBLIC libA::libA)
I get undefined reference to some libA's functions when I try to use libB in an app.
How can I tell CMake to include libA as part of libB?
What's the best practice for that?
I'd like to avoid any extra step (How to merge two "ar" static libraries into one?)
If you control the builds for both libA and libB, you can solve this by creating OBJECT libraries libA-obj and libB-obj. You would then link libA-obj to libA and then link both object libraries to libB.
Here's a more detailed sketch
cmake_minimum_required(VERSION 3.22)
project(example)
# ...
# Can be in subdirectory
add_library(libA-obj ${libA-srcs})
add_library(libA)
target_link_libraries(libA PUBLIC libA-obj)
# Can be in subdirectory
add_library(libB-obj ${libB-srcs})
add_library(libB)
target_link_libraries(libB PUBLIC libB-obj libA-obj)
# Can be in parent directory
add_executable(app ${app-srcs})
target_link_libraries(app PRIVATE libB)
You can add the object files that comprise libA to the sources of libB to include them:
target_sources(LibB PRIVATE $<TARGET_OBJECTS:LibA>)

How to set COMPILE_DEFINITIONS through cmake command line

I am building a couple of 3rd party libraries for integration.
There are two different source codes for two libs, libA and libB.
The libA has following, in its CMakeLists.txt
project(libA)
...
add_library(${PROJECT} ${SRCS})
target_link_library(${PROJECT} DOESNOTMATTER)
target_compile_definitions(${PROJECT_NAME} PUBLIC LETS_USE_GORILLA)
libA compilation is successful separately as shared lib.
libB is dependent on libA.
While compiling libB, it is expected that public compile definition of libA are automatically taken care by cmake to be available in libB. But they are not.
Now, if I add below target_compile_definitions in CMakeLists.txt of libB, it compiles successfully.
project(libB)
...
add_library(${PROJECT} ${SRCS})
target_link_library(${PROJECT} libA)
target_compile_definitions(${PROJECT_NAME} PUBLIC LETS_USE_GORILLA)
But, as this is a 3rd party code, I am not allowed to change the CMakeLists.txt.
Question - How can I pass some arguments in cmake command line to change the COMPILE_DEFINITIONS

Dependency between two subdirectories in CMake

In my root CMakeLists.txt, I have:
add_subdirectory(libs)
add_subdirectory(main)
In libs, I have my own CMakeLists.txt to build external projects.
In main, there is a CMakeLists.txt from another repository, which I do not control.
To build main, libs needs to be built. I do not know how to specify the
dependency between main and libs.
In libs, with my external projects lib1 and lib2, I used add_dependencies(lib1 lib2) and I have lib2 built before lib1. I did not find how to do that for
main and libs.
The difficulty for me is I have to mix external projects and subdirectories, and I did not find any answer or was not able to adapt them.
I converted add_subdirectory(main) into an external project. Since it is not possible to make a dependency on subdirectories, I use directly the inner targets. With all that I got:
include(ExternalProject)
add_subdirectory(libs)
ExternalProject_Add(main
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/main
...
)
add_dependencies(main lib1 lib2)

How to search for libraries in multiplatform cmake builds?

I am searching for a nice way to handle linked libs in cmake. In my case the cmake configuration file(CMakeLists.txt) is executed in Linux environments and on cygwin on Windows.
The build process contains two libs. libA is build from sources and only depends on the std. C API. libB is build, as well, from sources and includes the libA. The libs are build separately(with an own git repro).
By defining in cmake at "libB/CMakeLists.txt"
find_library (libB A)
I am linking libB against libA. When linking under cygwin, this line fails. When I change it to
find_library (libB ${CMAKE_LIBRARY_PATH}/static/libA.dll.a)
it works.
Both libs are build as shared libs.
"libA/CMakeLists.txt":
add_library(libA SHARED ${libA_source})
install(
TARGETS libA
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/static
)
and
"libB/CMakeLists.txt":
add_library(libB SHARED ${libB_source})
install(
TARGETS libB
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/static
)
Under Linux this works fine. The libs are placed into "/user/local/lib". Under Windows the libs are placed into "/user/local/lib/shared" + the dlls are placed into "/user/local/bin".
The statement to link libB against libA changes to ("libB/CMakeLists.txt"):
if (UNIX)
find_library (libB A)
elseif (CYGWIN)
find_library (libB ${CMAKE_LIBRARY_PATH}/static/libA.dll.a)
endif()
Any idea how to handle the linker references of these two builds in a simple - maybe - platform independent line?
This should work within your libB/CMakeLists.txt:
find_library(libA
NAMES A libA libA.so libA.dll libA.dll.a
HINTS ${CMAKE_INSTALL_FULL_LIBDIR}
)
target_link_libraries(libB ${libA})
Check the path to libA with
message(STATUS "libA=${libA}")