Build multiple examples with cmake

2019-08-25 05:25发布

问题:

My project uses the same core code, and i want to build the following structure

project
|
| - core_code
| - cmake 
| - CMakeLists.txt
| - example1
|     |
|     |- example1.cc
|     |- build
|
| - example2
|     |
|     |- example2.cc
|     |- build

I would like cmake to create targets in the build subdirectories for each example. So after I run cmake from projects directory then build, the structure should look like this:

project
    |
    | - core
    | - cmake 
    | - CMakeLists.txt
    | - example1
    |     |
    |     |- example1.cc
    |     |- build
    |          |- Makefile
    |          |- example1
    |
    | - example2
    |     |
    |     |- example2.cc
    |     |- build
    |          |- Makefile
    |          |- example2

What should I do in project/CMakeLists.txt?

回答1:

If you structure your project as follows:

project
    |
    |- CMakeLists.txt
    |- core
    |    |
    |    |- core.cc
    |    |- core.h
    |    |- CMakeLists.txt
    |
    |- example1
    |    |
    |    |- example1.cc
    |    |- CMakeLists.txt
    |
    |- example2
         |
         |- example2.cc
         |- CMakeLists.txt

Your project/CMakeLists.txt file just includes the other cmakelists files

project/CMakeLists.txt:

cmake_minimum_required (VERSION 3.5)
project (project CXX C)

add_subdirectory(core)
add_subdirectory(example1)
add_subdirectory(example2)

Your core/CMakeLists.txt file builds the core targets

project/core/CMakeLists.txt:

add_library(core core.cc)
target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

Your exampleN/CMakeLists.txt file builds the example targets

project/example1/CMakeLists.txt:

add_executable(example1 example.cc)
target_link_libraries(example1 core)

When you generate the build files, cmake mimics your directory structure in the build directory, so running the following commands would result in the below directory structure:

$ cd project
$ mkdir build
$ cd build
$ cmake ..

The resulting directory structure would look as follows:

project
    |
    |- CMakeLists.txt
    |- core
    |    |
    |    |- core.cc
    |    |- core.h
    |    |- CMakeLists.txt
    |
    |- example1
    |    |
    |    |- example1.cc
    |    |- CMakeLists.txt
    |
    |- example2
    |    |
    |    |- example2.cc
    |    |- CMakeLists.txt
    |                                  
    |- build
         |
         |- Makefile
         |- core
         |     |- Makefile
         |
         |- example1
         |     |- Makefile
         |     |- example1
         |
         |- example2
               |- Makefile
               |- example2

Now if you only want to build example2 for example, you can execute the following:

$ cd project/build/example2
$ make

The benefit of this is that it doesn't pollute your source tree with build files. If you want to blow away the build directory, you only need to delete one directory

$ rm -r project/build


回答2:

Assuming you have additional CMakeLists.txt somewhere, e.g. at cmake/example/CMakeLists.txt with content like:

add_executable(${EXAMPLE_NAME} ${EXAMPLE_DIR}/${EXAMPLE_NAME}.cc)

you may call it from project/CMakeLists.txt with:

# Build the first example in the 'example1/build' subdirectory
set(EXAMPLE_NAME example1)
set(EXAMPLE_DIR ${CMAKE_SOURCE_DIR}/example1)
add_subdirectory(cmake/example ${CMAKE_SOURCE_DIR}/example1/build)
# Build the second example in the 'example2/build' subdirectory
set(EXAMPLE_NAME example2)
set(EXAMPLE_DIR ${CMAKE_SOURCE_DIR}/example2)
add_subdirectory(cmake/example ${CMAKE_SOURCE_DIR}/example2/build)

Note, that CMake generates Makefile's only in the build directory, and the only way to change build directory is add_subdirectory() call. So you cannot get Makefile not in the top-level directory without additional CMakeLists.txt. But you may use single additional CMakeLists.txt for multiple build directories.


To be precise, you may use top-level CMakeLists.txt for examples too, but you need to make it "reentrant", which seems ugly for me.



标签: cmake