[CMake] Building in stages.

Michael Hertling mhertling at online.de
Tue Jun 22 12:24:41 EDT 2010


On 06/21/2010 05:41 PM, Magnus Therning wrote:
> On Mon, Jun 21, 2010 at 16:10, Michael Wild <themiwi at gmail.com> wrote:
>>
>>> I'm looking for some suggestions on how to tackle a problem with staged
>>> builds.
>>>
>>> In trying to convert a project which uses omake to build OCaml files I've
>>> stumbled on the issue that building one sub-part (bar) of the project needs
>>> the result of another sub-part (foo).  The twist is that foo is required
>>> already at the dependency-discovery stage of bar[1].  Is there some clever way
>>> of working around this?
>>>
>>> One obvious solution would be to simply skip automatic generation of
>>> dependencies for bar, but that feels a little naughty.  It feels about as
>>> naughty as how the previous build system just worked by ordering[2].
>>>
>>> Hopefully there's some better way of achieving this, any suggestions?
>>>
>>> /M
>>>
>>> [1] For those initiated in OCaml and its tools stack the former sub-part
>>> builds a custom filter for camlp4 which is then used in the latter sub-part.
>>> [2] omake is very similar to make and in this case the build of foo just
>>> happened before bar, and there was no attempt at automatic generation of
>>> dependencies at all.
>>
>> Well, if you need foo to be built before bar, just use add_dependencies(bar foo). File-level dependency scanning happens just before bar is built, so if I understand your question correctly, you should be fine now...
> 
> No, I need foo to be built before bar is inspected to gather its
> dependencies.  And dependencies for both foo and bar are gathered when
> calling `cmake` to generate the Makefiles. [...]

Look at the following CMakeLists.txt files:

CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(PRESTAGE C)
# Prebuild foo:
FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/prestage)
EXECUTE_PROCESS(
    COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/foo
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/prestage
)
EXECUTE_PROCESS(
    COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/prestage
)
# Use it to generate bar.c:
EXECUTE_PROCESS(
    COMMAND ${CMAKE_BINARY_DIR}/prestage/foo
    OUTPUT_FILE ${CMAKE_BINARY_DIR}/bar.c
)
# Business as usual:
ADD_SUBDIRECTORY(foo)
ADD_SUBDIRECTORY(bar)

foo/CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/foo.c "
\#include <stdio.h>
int main(void)
{
    printf(\"void bar(void){}\\n\"); return 0;
}
")
ADD_EXECUTABLE(foo ${CMAKE_CURRENT_BINARY_DIR}/foo.c)

bar/CMakeLists.txt:

ADD_LIBRARY(bar SHARED ${CMAKE_BINARY_DIR}/bar.c)

The top-level CMakeLists.txt uses EXECUTE_PROCESS() and "cmake --build"
to build "foo" in directory "prestage"; thereafter, it is used in the
remaining configuration process. As proof, "foo" generates the source
file for "bar" before the latter's subdirectory is entered by CMake.
Perhaps, you can adapt this approach to your purposes, i.e. to have
"foo" take part in gathering dependencies for "bar", but regarding
"cmake --build", in particular, I don't know if it works on systems
other than *nix, too.

Regards,

Michael


More information about the CMake mailing list