CMake relative path Libraries communication - cmake

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)

Related

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

pkg_check_modules doesn't resolve, because dependency doesn't have .pc file

There's a library, let's say libA. libA has its pkg-config file libA.pc. libA has a dependency, libB. libB is present in the build system (headers + compiled shared object), but doesn't have its own .pc file. Therefore pkg_check_modules is failing when trying to resolve libA. What is the proper way to solve this situation, should be added the *.pc file for libB?

Providing include directory outside source folder for static library users

I am developing a simple static C library for learning purposes using cmake.
Some projects like GLFW provide an include folder on the root, so library users can copy it and use it as an include directory.
In my library, I want to have an include folder on the root, so when I use the library on other projects, I can just copy this folder and set it as an include directory.
Here is a simplified folder structure of my library:
include
+--mylib.h
src
+--myheader.h
+--mysource.c
+--CMakeLists.txt
CmakeLists.txt
The src folder has my headers and implementation files, and a CMakeLists.txt for building a static library out of mysource.c.
The CMakeLists on the root folder just sets the project and adds src as a subdirectory.
I want the mylib.h file to have a #include <myheader.h>.
Here's a detour to talk about how I want to use it when it's done.
The idea is that when using the lib on another project, I can have something like this:
deps
+--include
+--mylib.h
src
+--main.c
And in the main.c file, include mylib.h and use what's defined on myheader.h
Here the detour ends, and I'm talking about my actual lib project again.
How can I achieve this using cmake? As far as I know, the mylib.h file needs to know it's including files from the src diretory, but I see no way of setting that, as for exemple in GLFW this directory does not have a CMakeLists.txt.
I am gonna quess that this is a design issue since it would make sense to you if you would have installed the library to a system before you tried to use it. That is, not using add_subdirectory() but find_library() at usage.
First, if you are using a external library, but not installing it, you would include all files in you deps-folder. All files then include source-files and so on and will be compiled besides you main.c. This is done with add_subdirectory(deps/MyLib) and later also included in you main-project.
Example:
add_subdirectory(deps/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
If you do not want to compile it all the time, then you must instruct cmake where it can find headers and library-files. Preferred way is to use find_library() which does some magic for you. Since you do not mention any installation i will assume that it does not exist and your only option is then to use add_subdirectory().
"I can just copy this folder and set it as an include directory."
CMake wants to handle these things for you so you should never copy headers around. You should either use add_subdirectory() to include a project/headers or make use of the find_library() which make sure you find where the headers are in the system.
I suggest that you push yourself to learn howto install a library into a system and how to utilize it later, but only by using find_library(). Then the library will be global for all projects and also not duplicated.
Adding some kind of psudo-code in hope it all makes more sense. Although it is around add_subdirectory() since the code for installing is quite large unfortunately.
CMakeLists.txt for main.c
cmake_minimum_required(VERSION 3.8)
project(MyLibTest)
add_executable(${PROJECT_NAME}
src/main.c
)
add_subdirectory(external/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
CMakeLists.txt for library
cmake_minimum_required(VERSION 3.8)
project(MyLib)
add_library(${PROJECT_NAME} STATIC
src/MyLib.c
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
The structure for the project would then be:
/
external/MyLib
external/MyLib/src
MyLib.c
external/MyLib/include
MyLib.h
src
main.c
CMakeLists.txt

Link one project to another 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.