0

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.

3
  • I think that your problem could be solved with add_subdirectory, but you already tried. Can you share more details about what happens when you use this command? Commented Dec 28, 2022 at 13:52
  • @ViniciusAlmada when I am targeting a source from a subdirectory, I have to name a source but the source can be either projectA/outA or projectB/outB. So, whenever I use libraryX from projectA I have to edit CMakeFiles and vice versa. Or is it ok to name both executables as out an Commented Dec 28, 2022 at 17:09
  • I guess you need to set up a package repository like e.g. Conan Commented Dec 28, 2022 at 18:21

1 Answer 1

1

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 ;).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! Just adding the subdirectories without changing anything in the libraries, worked for me. Now, whenever I build a projectA it also builds all the added libraries!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.