Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cmake, add_custom_command with dependencies from a different directory

Tags:

cmake

I have a question about CMake which seems to be commonly asked here, but none of the answers seem to solve my problem.

In the details subdirectory, there is a CMakeLists.txt which contains:

add_custom_command(OUTPUT part.out
                   COMMAND foo --input=part.src --output=part.out
                   DEPENDS part.src)

add_custom_target(part_out
                  DEPENDS part.out)

In the main directory there is a CMakeLists.txt which uses part.out for generating another file:

add_custom_command(OUTPUT full.out
                   COMMAND bar --input=./details/part.out --output=full.out)

add_custom_target(full_out
                  DEPENDS full.out)

The problem is that I want 3 things to happen here:

  1. if part.out doesn't exist it needs to be generated
  2. if part.out is out of date (part.src is newer than part.out) I want it to be regenerated
  3. if full.out is out of date (part.out is newer than full.out, or full.out desn't exist) I want it to be (re)generated

So if I add DEPENDS ./details/part.out to add_custom_command(OUTPUT full.out) I will achieve points 2 and 3, but not point 1, because if I delete part.out and then I call make full_out I'll get an error that there is no rule to make ./details/part.out (as it is a rule from another directory).

If I add DEPENDS full_out to add_custom_command(OUTPUT full.out) or to add_custom_target(full_out) I'll achieve points 1 and 2, but not 3, because even if part.out was regenerated, a full.out will not be regenerated, as it doesn't depend on the part.out file itself.

So how can I connect both scenarios? I was thinking about adding both DEPENDS but how do I know if that will always work? I mean in such case the order of build will matter here.

like image 773
Michał Walenciak Avatar asked Nov 20 '12 09:11

Michał Walenciak


1 Answers

CMake docs for add_custom_target:

By default nothing depends on the custom target. Use ADD_DEPENDENCIES to add dependencies to or from other targets.

So I suggest to "connect" the targets with

ADD_DEPENDENCIES( full_out part_out )

EDIT: Working example

As it turned out, you need to set the source file properties for part.out

Here is my working example (tried under Windows with VS2008):

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8 )
project( full )

add_subdirectory( details )

add_custom_command( OUTPUT full.out 
               COMMAND ${CMAKE_COMMAND} -E copy ./details/part.out full.out
               DEPENDS details/part.out 
               )


add_custom_target( full_out
               DEPENDS full.out details/part.out details/part.src
              )


set_source_files_properties( details/part.out PROPERTIES GENERATED TRUE ) 


add_dependencies( full_out part_out )

details/CMakeLists.txt:

cmake_minimum_required(VERSION 2.8 )
project(part)

add_custom_command(OUTPUT part.out
               COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/part.src part.out
               DEPENDS part.src)

add_custom_target(part_out
              DEPENDS part.out)

This example worked for all of your 3 stated cases.

like image 174
Johannes S. Avatar answered Oct 26 '22 10:10

Johannes S.