Hannes Ovrén
Hannes Ovrén

Reputation: 21831

How can I build multiple targets using cmake --build

I have a CMake build with a bunch of different targets A, B, C, etc. An external application is tasked with building, and currently does so by calling

cmake --build .

However, this builds all targets, and sometimes I only want to build a subset, like A and B but not C. The --target flag can only be given once, and only accepts a single target.

I guess I could let CMake generate the appropriate Makefile, and then call make A B explicitly, but that takes away the nice thing about cmake --build being build system agnostic.

Is there a nice way to solve this?

Upvotes: 22

Views: 31108

Answers (3)

Ben
Ben

Reputation: 9703

I don't know of a built-in way, but this does it:

$ BUILD_DIR=./cmake-build-debug; cmake --build $BUILD_DIR --target help | awk -F ':' '{print $1}' | grep $YOUR_FILTER | xargs cmake --build $BUILD_DIR --target

That is, take cmake --build $BUILD_DIR --target help, strip off the trailing :... stuff from the lines, filter it, then call cmake --build $BUILD_DIR $THAT (possibly splitting up $THAT to multiple calls as xargs sees fit).

Or if you'd rather,

$ BUILD_DIR=./cmake-build-debug; cmake --build $BUILD_DIR --target $(cmake --build $BUILD_DIR --target help | awk -F ':' '{print $1}' | grep $YOUR_FILTER | paste -sd " " -)

which collects your target into one space-separated line with paste -sd " " - and then calls cmake --build $BUILD_DIR --target $THOSE_SPACE_DELIMITED_TARGETS.

Upvotes: 0

ComicSansMS
ComicSansMS

Reputation: 54589

CMake version 3.15 added support for this feature. Simply list all targets on the command line as follows:

cmake --build . --target Library1 Library2

Upvotes: 38

user5164080
user5164080

Reputation:

Maybe not the "nicest" way, but definitely a solution would be to introduce a custom top-level target and make the needed targets depend on it. For example:

cmake_minimum_required(VERSION 3.9) # can be lower

project(demo LANGUAGES C)

file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/a.c"
    [[
    #include <stdio.h>
    int main(void) { printf("a\n"); return 0; }
    ]])
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/b.c"
    [[
    #include <stdio.h>
    int main(void) { printf("b\n"); return 0; }
    ]])
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/c.c"
    [[
    #include <stdio.h>
    int main(void) { printf("c\n"); return 0; }
    ]])

add_executable(A "${CMAKE_CURRENT_BINARY_DIR}/a.c")
add_executable(B "${CMAKE_CURRENT_BINARY_DIR}/b.c")
add_executable(C "${CMAKE_CURRENT_BINARY_DIR}/c.c")

set(DEMO_ENABLE_TARGETS "" CACHE
    STRING "Targets to be built in demo simultaneously (default: none)")

if(NOT "${DEMO_ENABLE_TARGETS}" STREQUAL "")
    add_custom_target(enabled_targets)
    foreach(target IN LISTS DEMO_ENABLE_TARGETS)
        add_dependencies(enabled_targets ${target})
    endforeach()
endif()

Then invoke

$ cmake -H. -Bbuild -DDEMO_ENABLE_TARGETS="B;C"
$ cmake --build build --target enabled_targets

and only B and C will be built.

Note that you have to specify DEMO_ENABLE_TARGETS's contents as a list, otherwise it'll break.

Upvotes: 4

Related Questions