Wow. Thanks Michael. That's a very thorough answer. I like your idea, but it just doesn't feel right. It seems to me that the right way to do it would be to patch CMake.
There's a base class for the dependency scanners and several derived classes for C, java, fortan, etc. Would it not be easy to just derive another class for each file type I need? These dependency scanner classes seemed to just regex each line in the file looking for "include" or "import", or some other language specific keyword. That would work for me, I could just scan for "m4_include". In the mean time however, I think I could slip in one of your solutions. Thanks again. --- Aaron Wright From: Michael Hertling <[email protected]> To: [email protected] Date: 04/05/2011 08:36 AM Subject: Re: [CMake] Dependencies scanning for non-c/c++ files Sent by: [email protected] On 04/03/2011 02:25 AM, [email protected] wrote: > I have some m4 files in my build that include other m4 files, so there's a > dependency between m4 files that can change at any time. I can calculate > the dependency at configure time, but what can I do when the files change > and I need to recalculate the dependencies? This is obviously handled for > c/c++ files by CMake. Any ideas? > > --- > Aaron Wright Build-time dependency scanning without resorting to CMake's built-in dependency scanner is possible but ugly, in a sort. First of all, you need a custom target which suitably sets up the dependencies, and you need to make the CMakeLists.txt file depend on them so that a change of the dependencies will trigger a reconfiguration-before-rebuild in order to recognize these new dependencies. In the following examples, this gets done by a CMake script that gathers all files in a denoted directory and writes their names to a file containing a CMake SET() command, and this file gets included in the CMakeLists.txt. In that way, changing dependencies invalidate the CMakeLists.txt file, and the filenames - assigned to a variable by the SET() command - are used to populate the OBJECT_DEPENDS property of a target, so the latter gets also rebuilt when those files are touched. Now, the key consideration is that you need two independent Make runs for the home-brewed build-time dependency scanning to work: The first run triggers the above-mentioned custom target to update dependencies, and the second run builds your project with up-to-date dependencies - maybe after a reconfiguration. AFAICS, this cannot be done in one go because of the possibly needed intermediate CMake run to reconfigure. In order to perform these two independent Make runs, you might: 1) Do it manually, e.g. "make dependencies; make". The downside is that you'll miss changed dependencies if you forget to perform the "dependencies" run. 2) For each affected target, introduce a helper target which triggers the dependencies target and subsequently builds the actual target via "cmake --build". Look at the following: # CMakeLists.txt: CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) PROJECT(DEPENDENCIES C) ADD_CUSTOM_TARGET(dependencies ${CMAKE_COMMAND} -DTEMPLATE=${CMAKE_SOURCE_DIR}/filelist.cmake.in -DVARIABLE=DEPENDENCIES -DDIRECTORY=${CMAKE_SOURCE_DIR}/dependencies -DOUTPUT=${CMAKE_BINARY_DIR}/dependencies.txt -P ${CMAKE_SOURCE_DIR}/dependencies.cmake) IF(NOT EXISTS ${CMAKE_BINARY_DIR}/dependencies.txt) EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -DTEMPLATE=${CMAKE_SOURCE_DIR}/filelist.cmake.in -DVARIABLE=DEPENDENCIES -DDIRECTORY=${CMAKE_SOURCE_DIR}/dependencies -DOUTPUT=${CMAKE_BINARY_DIR}/dependencies.txt -P ${CMAKE_SOURCE_DIR}/dependencies.cmake) ENDIF() FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n") INCLUDE(${CMAKE_BINARY_DIR}/dependencies.txt) SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/main.c PROPERTIES OBJECT_DEPENDS "${DEPENDENCIES}") ADD_EXECUTABLE(main0 EXCLUDE_FROM_ALL main.c) ADD_CUSTOM_TARGET(main ALL COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target dependencies COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target main0) # dependencies.cmake: FILE(GLOB FILES ${DIRECTORY}/*) CONFIGURE_FILE(${TEMPLATE} ${OUTPUT} @ONLY) # filelist.cmake.in: SET(@VARIABLE@ @FILES@) The dependencies target runs the dependencies.cmake script which generates the dependencies.txt file with the filenames from the dependencies directory; the dependencies.txt file must be created once initially and it contains the above-mentioned SET() command, i.e. SET(DEPENDENCIES <dependencies-directory-files>). The actual target is main0, but the target which is triggered when building the project is main, and it's this main target that performs the two independent Make runs using the CMake "--build" option. Note that due to the use of CONFIGULE_FILE(), the dependencies target can run each time without causing the project's reconfiguration, provided the dependencies have not changed. However, if a file in the dependencies directory is just touched, the main target gets rebuilt due to the OBJECT_DEPENDS property. 3) Use a helper project which allows unmodified target names: # CMakeLists.txt: CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) PROJECT(DEPENDENCIES C) EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/helper) EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -DTOPLEVEL=${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/helper WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/helper) ADD_CUSTOM_TARGET(dependencies ${CMAKE_COMMAND} -DTEMPLATE=${CMAKE_SOURCE_DIR}/filelist.cmake.in -DVARIABLE=DEPENDENCIES -DDIRECTORY=${CMAKE_SOURCE_DIR}/dependencies -DOUTPUT=${CMAKE_BINARY_DIR}/dependencies.txt -P ${CMAKE_SOURCE_DIR}/dependencies.cmake) IF(NOT EXISTS ${CMAKE_BINARY_DIR}/dependencies.txt) EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -DTEMPLATE=${CMAKE_SOURCE_DIR}/filelist.cmake.in -DVARIABLE=DEPENDENCIES -DDIRECTORY=${CMAKE_SOURCE_DIR}/dependencies -DOUTPUT=${CMAKE_BINARY_DIR}/dependencies.txt -P ${CMAKE_SOURCE_DIR}/dependencies.cmake) ENDIF() FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n") INCLUDE(${CMAKE_BINARY_DIR}/dependencies.txt) SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/main.c PROPERTIES OBJECT_DEPENDS "${DEPENDENCIES}") ADD_EXECUTABLE(main main.c) # helper/CMakeLists.txt: CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) PROJECT(HELPER NONE) ADD_CUSTOM_TARGET(helper ALL COMMAND ${CMAKE_COMMAND} --build ${TOPLEVEL} --target dependencies COMMAND ${CMAKE_COMMAND} --build ${TOPLEVEL}) ADD_CUSTOM_TARGET(main COMMAND ${CMAKE_COMMAND} --build ${TOPLEVEL} --target dependencies COMMAND ${CMAKE_COMMAND} --build ${TOPLEVEL} --target main) The dependencies.cmake script and filelist.cmake.in template are the same as in 2). Effectively, this means you'll have the helper targets in the helper project so there's no need to have supplementary target names like main0. Nevertheless, it also means that you need to build your project or denoted targets from the helper project's build tree, e.g. "make -C helper" or "make -C helper main" if you reside in your actual project's build tree as usual. Besides, the dependencies.txt file does not need to contain a SET() command; it's just handy to set the OBJECT_DEPENDS property so you can handle time-stamp dependencies along with file-level ones. In fact, the dependencies.txt file just needs to be capable of being included in CMakeLists.txt and get touched when the dependencies you want to track have changed. If you do not use OBJECT_DEPENDS in the above-noted manner, the filelist.cmake.in template could even comprise solely a simple comment, e.g. "# @FILES@". Currently, because of the two Make runs, I don't see a possibility to set up things in a way so that this kind of dependency scanning works as it does with CMake's built-in scanner, but perhaps, you can adapt one of these approaches to suit your needs. Regards, Michael _______________________________________________ Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://www.cmake.org/mailman/listinfo/cmake _______________________________________________ Powered by www.kitware.com Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Follow this link to subscribe/unsubscribe: http://www.cmake.org/mailman/listinfo/cmake
