The Linux Page

Writing a shell command on multiple lines in a cmake script using ADD_CUSTOM_COMMAND()

Long command can be written as separate strings in cmake

Today I really wanted to write a command on multiple lines because I pass many command line options to it and it started to look really very long (much wider than my editor width).

There are many entries on how to run multiple commands: write one ADD_CUSTOM_COMMAND() per command. Simple enough. If you really only want one single ADD_CUSTOM_COMMAND(), you can always write a shell script (a .sh file) and put all the commands in there.

However, writing a single command with many command line options separated by spaces on multiple line is not well explained in the ADD_CUSTOM_COMMAND() (I'm sure the syntax is explained somewhere, cmake is well documented otherwise, but it's hard to find the info you need from one place to another in such circumstances...)

The fact is that you can write any number of quoted strings and cmake will concatenate them adding a space in between each one of them. Spaces within those strings will, however, be escaped with a backslash.

In my case, I wanted the following on multiple lines and using the quotes work, but look closely:

add_custom_command(
    OUTPUT ${TLD_DATA_C}
    COMMAND "tld_parser"
                "--source"
                    "${CMAKE_SOURCE_DIR}/conf/tlds"
                "--verify"
                "--output-json"
                    "--include-offsets"
                "--c-file"
                    "${TLD_DATA_C}"
                "${PROJECT_BINARY_DIR}/tlds.tld"
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    MAIN_DEPENDENCY tld_parser
    DEPENDS ${TLD_FILES}
)

Every single command line argument must be in a separate string.

So I can't have "--source ${CMAKE_SOURCE_DIR}/conf/tlds" on a single line. I have to have two separate strings (although I could put them on a single line... but I thouhgt that could be harder to read).

Similarly, the two options "--output-json" and "--include-offsets" are on separate lines even though they work in concert and it would make sense to have them together.

With that in hands, though, it works as expected and the result is one long command in the final Makefile (good luck with the horizontal scrolling):

libtld/tld_data.c: libtld/tld_parser
        @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --blue --bold --progress-dir=/home/snapwebsites/snapcpp/BUILD/Debug/contrib/libtld/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Generating tld_data.c"
        cd /home/snapwebsites/snapcpp/contrib/libtld && /home/snapwebsites/snapcpp/BUILD/Debug/contrib/libtld/libtld/tld_parser --source /home/snapwebsites/snapcpp/contrib/libtld/conf/tlds --verify --output-json --include-offsets --c-file /home/snapwebsites/snapcpp/BUILD/Debug/contrib/libtld/libtld/tld_data.c /home/snapwebsites/snapcpp/BUILD/Debug/contrib/libtld/libtld/tlds.tld

Note that this feature is available to pretty much all commands. Lists of strings automatically get concatenated in this way.