I am given several projects (git repos) and each of them depends on a number of libraries (also git repos). Every project has just one target executable and links libraries from other repos.
My file structure:
├── libraries
│ ├── libraryX (git:master)
│ │ ├── build
│ │ │ └── libX.so
│ │ ├── CMakeLists.txt
│ │ ├── fileX.cpp
│ │ └── fileX.h
│ ├── libraryY (git:master)
│ │ ├── build
│ │ │ └── libY.so
│ │ ├── CMakeLists.txt
│ │ ├── fileY.cpp
│ │ └── fileY.h
│ └── libraryZ (git:master)
│ ├── build
│ │ └── libZ.so
│ ├── CMakeLists.txt
│ ├── fileZ.cpp
│ └── fileZ.h
└── projects
├── projectA (git:master)
│ ├── build
│ │ └── outA
│ ├── CMakeLists.txt
│ └── mainA.cpp
└── projectB (git:master)
├── build
│ └── outB
├── CMakeLists.txt
└── mainB.cpp
This is an example CMakeLists.txt
file inside libraryX
:
cmake_minimum_required(VERSION 3.6)
project(libraryX LANGUAGES CXX)
set(libraries $ENV{LIBRARIES})
set(projects $ENV{PROJECTS})
add_library(libX SHARED fileX.cpp)
target_include_directories(libX PUBLIC ${libraries}/libraryX/)
Currently I am building every library manually, which generates *.so
files and then I go to the project and build the executable. This is an example CMakeLists.txt
from inside projectA
:
cmake_minimum_required(VERSION 3.6)
project(projectA LANGUAGES CXX)
set(libraries $ENV{LIBRARIES})
set(projects $ENV{PROJECTS})
add_executable(outA mainA.cpp)
target_include_directories(outA
PUBLIC
${libraries}/libraryX/
${libraries}/libraryY/
${libraries}/libraryZ/
${projects}/projectA/
)
target_link_libraries(outA
${libraries}/libraryX/build/libX.so
${libraries}/libraryY/build/libY.so
${libraries}/libraryZ/build/libZ.so
)
I am only interested in building/running one project (e.g. projectA/
) at a time, but I don't want to manually precompile every library every time I make changes.
Also, I cannot move libraries/
under the project (e.g. projectA/libraries/libraryX
) because projectB/
also depends on them, and I don't like having two clones of the same repository in one computer in sibling folders. I also cannot change and rearrange the content of repositories to suit myself, because different teams are working on them and plan to release them as full packages installable from apt-get in the future. Finally, I don't want to use a single top-level CMakeLists.txt
inside the workspace because the projects A and B are independent from each other.
I tried looking into add_subdirectory
and target_sources
but could not understand how to target a source if I want the same library to be used by different executables in projectA
and projectB
.
Of course, I can run a bash script that builds cmakes in every library, but I thought that this is a job of CMake to do such things. I am clearly not seeing some obvious solution here.
Can anyone help me to force CMake to precompile the library before linking them to the target?
Thanks!
P.S. How can I tell CMake to compile *.dll
files instead of *.so
, and *.exe
instead of Linux binaries?
I have read and watched a lot of tutorials and read a lot of stackoverflow answers about the architecture of the CMake projects. I tried to run the project in Visual Studio on Windows in hopes of it figuring it out itself -- didn't really help. I wrote a bash script that compiles libraries before linking them but it feels wrong, because I was promised that CMake actually does this thing for me. I also tried to use subdirectory system as mentioned in another stackoverflow answer but it did not really succeed.
CodePudding user response:
Your libraryX/CMakeLists.txt
would look like this:
cmake_minimum_required(VERSION 3.6)
project(libraryX LANGUAGES CXX)
add_library(libX SHARED fileX.cpp)
target_include_directories(
libX
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
At the root directory of all sub-projects, you may add the CMakeLists.txt
which performs add_subdirectory()
for all libraries (first) and binaries (last).
Then in the projectX/CMakeLists.txt
just link to CMake targets you need:
cmake_minimum_required(VERSION 3.6)
project(projectX LANGUAGES CXX)
add_executable(outA mainA.cpp)
target_include_directories(
outA
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
# NOTE No need for any other paths
)
target_link_libraries(
outA
PRIVATE
libX
libY
libZ
)
Update (after I spot that these are separate git repos):
You need to export your library targets (build and install 'em into the same prefix) and use find_package(libX)
in your projectX/CMakeLists.txt
to find a target to link with.
Having separate libs is nice (compared to a monorepo ;).