[CMake] static library from several subdirectories
Michael Wild
themiwi at gmail.com
Mon Mar 22 11:09:42 EDT 2010
On 22. Mar, 2010, at 15:22 , Verweij, Arjen wrote:
> Hi,
>
>> From: Michael Wild [mailto:themiwi at gmail.com]
>
>>>> You have to call ADD_SOURCES for all your sources BEFORE you do the
>>>> ADD_LIBRARY call.
>>>
>>> I am already doing this, but since the files I was adding to the
>> library didn't exist, the call failed. I somehow expected cmake to start
>> executing the custom command since there was a previously defined
>> dependency, but apparently cmake wasn't set up for the way I'm
>> mistreating it :)
>>>
>>> What triggers a custom command to be executed? With your help I have
>> arrived at:
>>
>>
>> You should add a "DEPENDS <input_file1> <input_file2> ..." option to
>> your ADD_CUSTOM_COMMAND calls, then CMake will know when to invoke it,
>> otherwise it can't know anything about the dependency.
>
> Alright. I have spent a considerable amount of time experimenting, rewriting and testing. I have reduced my problem to hello world inside a hello.cr file. add_sources() has been molested and reduced to a mere shadow of its former glory. With or without DEPENDS doesn't change matters, although I'm sure without is bad form. Layout:
>
> CMakeLists.txt (code below)
> h -- CMakeLists.txt (it just calls add_sources() -- without any arguments)
> | -- hello.cr (your typical hello world)
>
> So, when I call add_sources() directly from the top level CMakeLists.txt file, I obtain my executable "test". If I comment out the add_sources() call, and use add_subdirectory(h) instead, and call add_sources() from there, it fails. The complaint is that it cannot find source file "hello.c" Apparently the problem is that add_custom_command() calls are local to the directory they are called in, and since the executable is assembled from a list on a higher level, it expects to find the source file on disc already :(
>
> PROJECT(Test)
> enable_language( C )
> cmake_minimum_required(VERSION 2.8)
>
> function (add_sources)
> define_property(GLOBAL PROPERTY list BRIEF_DOCS "brief" FULL_DOCS "full")
>
> SET ( out_file "/mnt/usr3/people/verweija/cmake2/build/h/hello.c" )
> SET ( in_file "/mnt/usr3/people/verweija/cmake2/h/hello.cr" )
>
> ADD_CUSTOM_COMMAND(
> OUTPUT ${out_file}
> COMMAND ${CMAKE_COMMAND} -E copy ${in_file} ${out_file}
> DEPENDS "/mnt/usr3/people/verweija/cmake2/h/hello.cr"
> )
>
> LIST( APPEND mylist ${out_file} )
>
> set_property(GLOBAL APPEND PROPERTY "list" "${mylist}")
> endfunction(add_sources)
>
> add_sources()
> #add_subdirectory( h )
>
> get_property(list GLOBAL PROPERTY list)
> message ( STATUS list=${list} )
> ADD_EXECUTABLE( "test" ${list} )
>
> I have found some threads about this, and I will be reading them shortly :)
>
> Regards,
> Arjen
Problem is the following:
Dependencies between stuff in different directories only work for top-level targets (add_library, add_executable and add_custom_target). So, you would need to add a ADD_CUSTOM_TARGET call with a unique target name in your ADD_SOURCES function, add that name to a global list (as you do with the sources) and then after your ADD_EXECUTABLE call you have to do an ADD_DEPENDENCIES. Further, you need to tell CMake at the top-level that the sources are generated by setting the source file property GENERATED to TRUE.
All very complicated and error prone. So I suggest, you move the whole logic of your preprocessing to your top-level CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(example)
# function to collect all the sources from sub-directories
# into a single list
function(add_sources)
get_property(is_defined GLOBAL PROPERTY SRCS_LIST DEFINED)
if(NOT is_defined)
define_property(GLOBAL PROPERTY SRCS_LIST
BRIEF_DOCS "List of source files"
FULL_DOCS "List of source files to be compiled in one library")
endif()
# make absolute paths
set(SRCS)
foreach(s IN LISTS ARGN)
if(NOT IS_ABSOLUTE "${s}")
get_filename_component(s "${s}" ABSOLUTE)
endif()
list(APPEND SRCS "${s}")
endforeach()
# append to global list
set_property(GLOBAL APPEND PROPERTY SRCS_LIST "${SRCS}")
endfunction(add_sources)
# add subdirectories
add_subdirectory(src)
# preprocess sources
set(PREP_SRCS)
get_property(SRCS GLOBAL PROPERTY SRCS_LIST)
foreach(s IN LISTS SRCS)
file(RELATIVE_PATH rs "${CMAKE_CURRENT_SOURCE_DIR}" "${s}")
string(REGEX REPLACE "r$" "" o "${CMAKE_CURRENT_BINARY_DIR}/${rs}")
add_custom_command(
OUTPUT "${o}"
COMMAND ${CMAKE_COMMAND} -E copy "${s}" "${o}"
DEPENDS "${s}"
COMMENT "Creating ${o}"
VERBATIM
)
list(APPEND PREP_SRCS "${o}")
endforeach()
# add executable
add_executable(example ${PREP_SRCS})
HTH
Michael
More information about the CMake
mailing list