0

I would like to know how I can configure and build a subproject during the configuration phase of my main project. In addition, I would like to link the main executable against this subproject during the build phase of the main executable. In the past, there has already been a similar question on this website: previous question + answer (however, in that question, the linking of the subproject and the main executable is not discussed). I tried following the answer to that question, but I cannot get it to work properly in my case. I will give a detailed overview of a sample situation below. Could anyone tell me what I am doing wrong?


Consider the following file tree:

.
├── CMakeLists.txt
├── Greetings
│   ├── CMakeLists.txt
│   ├── headers
│   │   └── greetings.h
│   └── src
│       └── greetings.cpp
├── other_project
│   └── CMakeLists.txt
└── src
    └── main.cpp

5 directories, 6 files

First of all, I will discuss the ./Greetings directory. This directory has two subdirectories, namely headers and src. The former contains a header file for the greetings library, while the latter contains the source code (single file). These files consist of the following code:

./Greetings/headers/greetings.h

#ifndef _greetings_h_
#define _greetings_h_

#include <iostream>

namespace greetings {
    void hello();
} // greetings

#endif // _greetings_h_

./Greetings/src/greetings.cpp

#include "greetings.h"

void greetings::hello() {
    std::cout << "Hello!" << std::endl;
}

In addition to these two subdirectories, the ./Greetings folder contains a CMakeLists.txt, which has the following contents:

./Greetings/CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

project(Greetings
    LANGUAGES CXX
)

add_library(greetings)
target_sources(greetings
    PRIVATE "src/greetings.cpp"
            "headers/greetings.h"
)

target_include_directories(greetings
    PUBLIC "headers"
)

As you can see, this CMakeLists.txt file is responsible for creating a greetings library (libgreetings.a). Note that you can build the greetings library as a stand-alone using this CMakeLists.txt file.

The second part I will discuss is the source code for the main executable, which is located in the ./src folder. The file is called main.cpp and contains the following code:

./src/main.cpp

#include "greetings.h"

int main() {
    greetings::hello();
    return 0;
}

So, the code simply calls a function from the greetings library. To summarise, in my case the greetings library is the subproject and the main project consists of the compiled version of ./src/main.cpp.

Normally, to link the main executable with the greetings library, I would simply use a combination of add_subdirectory and target_link_libraries in the top-level CMakeLists.txt. However, I want to do it differently. During the configuration phase of the main executable (./src/main.cpp in this case), I want to configure and build the greetings library. This means that at the end of the configuration phase of the main executable (so before I start building the main executable!), the complete compilation of the greetings library should be finished. Then, once I build the main executable, I want to link it against the greetings library (libgreetings.a). (note: I know the behaviour I described above is not intuitive in this situation. However, I require this behaviour for my actual code. The code I have given above is merely a simplified example).

I currently try to achieve this behaviour as follows (based on the previous question + answer): in my top-level CMakeLists.txt, I have the following code.

./CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

project(MyApplication
    LANGUAGES CXX
)

add_executable(myexe)
target_sources(myexe
    PRIVATE "src/main.cpp"
)

file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/other_project)
execute_process(
    COMMAND ${CMAKE_COMMAND} --build . ${CMAKE_SOURCE_DIR}/other_project
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/other_project
)

I start with defining the usual code. The important part is located at the end. Here, I first create a directory, after which I use the execute_process function to call an external CMakeLists.txt. This CMakeLists.txt is located in the ./other_project folder and contains the following code:

./other_project/CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

project(other_project)

include(ExternalProject)
ExternalProject_Add(greetproj
    SOURCE_DIR "${CMAKE_SOURCE_DIR}/Greetings"
    BINARY_DIR "${CMAKE_BINARY_DIR}/Greetings"
)

Basically, this CMakeLists.txt is responsible for configuring and building the greetings library during the configuration phase of the main executable.

Unfortunately, the solution given above does not work for me. When I perform an out-of-source build (to a ./build directory), I get the following output:

Unknown argument ./other_project
Usage: cmake --build <dir> [options] [-- [native-options]]
Options:
  <dir>          = Project binary directory to be built.
  --parallel [<jobs>], -j [<jobs>]
                 = Build in parallel using the given number of jobs.
                   If <jobs> is omitted the native build tool's
                   default number is used.
                   The CMAKE_BUILD_PARALLEL_LEVEL environment variable
                   specifies a default parallel level when this option
                   is not given.
  --target <tgt>..., -t <tgt>...
                 = Build <tgt> instead of default targets.
  --config <cfg> = For multi-configuration tools, choose <cfg>.
  --clean-first  = Build target 'clean' first, then build.
                   (To clean only, use --target 'clean'.)
  --verbose, -v  = Enable verbose output - if supported - including
                   the build commands to be executed.
  --             = Pass remaining options to the native tool.
-- Configuring done
-- Generating done
-- Build files have been written to: ./build

To my best understanding, I applied the solution given in the previous question I referred to earlier. However, I must be doing something wrong, as it is clearly not working. In addition, even if this is solved, I have no clue how I could successfully link the greetings library into the main executable.

Thank you for reading this. Any help is appreciated.

DeX97
  • 637
  • 3
  • 12
  • 2
    You could add install commands including `install(EXPORT)` into the `greetings` lib and simply configure, build& install the lib to the binary dir using the same cmake commands you'd use from the command line and then use `find_package` to get the lib as imported target... – fabian Feb 01 '21 at 19:38
  • 1
    With `--build` option CMake only **builds** the project, but you need to **configure** the project first. Without changing directory, configuring the project could be achieved with `-S` and `-B` options: `COMMAND ${CMAKE_COMMAND} -B ${CMAKE_BINARY_DIR}/other_project -S ${CMAKE_SOURCE_DIR}/other_project`. – Tsyvarev Feb 01 '21 at 21:16
  • 1
    I have fixed [my answer](https://stackoverflow.com/questions/37553280/how-to-build-cmake-externalproject-while-configurating-main-one) you refers to. – Tsyvarev Feb 01 '21 at 21:32

0 Answers0