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.