On 05/05/2011 05:14 PM, Pere Mato Vila wrote: > > >> If I understand correctly, it's this second point which causes your >> astonishment, but it already happens during the build phase in the >> build tree, not just when installing with "make install", right? > > Yes, this is indeed my astonishment. I understand that for 'normal' projects > this re-link in the build tree will be almost unnoticeable. Unfortunately in > our project we build at least one executable using these libraries that is a > code generator and therefore all generated code for many other libraries gets > regenerated, re-compiled and re-linked. It is a major re-build just for > changing the length of the installation directory. So, I see that the only > solution I have is to avoid using CMAKE_INSTALL_RPATH. Thanks very much for > your explanations. > Regards, > > Pere
Uuhhh, a code generator with its far-reaching dependency implications is quite unpleasant in this regard, indeed. Perhaps, there's a chance to accomplish nearly what you have in mind. If I've got it right, the problem is that one can not distinguish the "good" relink operations, i.e. due to changes in source code or prerequisite targets, from the "bad" ones, i.e. due to the placeholder mechanism when the RPATH has changed. So, a possible approach to prevent the code generator from becoming out-of-date due to a mere RPATH change in its prerequisite libraries is to dissolve the generator's dependency on the affected libraries, take it into account by other means and ignore it when solely a new RPATH is written to the binaries. See the following CMakeLists.txt file et al. for an example how to achieve this: CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) PROJECT(RPATH C) SET(CMAKE_VERBOSE_MAKEFILE ON) ADD_EXECUTABLE(gen gen.c) ADD_CUSTOM_COMMAND(OUTPUT main.c COMMAND gen > main.c DEPENDS gen) ADD_EXECUTABLE(main main.c) SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") ADD_LIBRARY(f SHARED f.c) IF(NOT RPATH) ADD_CUSTOM_COMMAND(TARGET f POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:f> ${CMAKE_BINARY_DIR}/libf_gen.so) ENDIF() ADD_LIBRARY(g SHARED g.c) IF(NOT RPATH) ADD_CUSTOM_COMMAND(TARGET g POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:g> ${CMAKE_BINARY_DIR}/libg_gen.so) ENDIF() INSTALL(TARGETS f g LIBRARY DESTINATION lib) ADD_CUSTOM_TARGET(gen_libs COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target f COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target g) ADD_DEPENDENCIES(gen gen_libs) ADD_LIBRARY(f_gen SHARED IMPORTED) SET_TARGET_PROPERTIES(f_gen PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/libf_gen.so) ADD_LIBRARY(g_gen SHARED IMPORTED) SET_TARGET_PROPERTIES(g_gen PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/libg_gen.so) TARGET_LINK_LIBRARIES(gen f_gen g_gen) /* f.c: */ void f(void){} /* g.c: */ void g(void){} /* gen.c: */ #include <stdio.h> int main(void) { printf("int main(void){return 0;}\n"); return 0; } The executable gen is a code generator that produces the main target's source code and is linked against the libraries f and g which in turn are affected by the RPATH placeholder mechanism. If I'm not mistaken, this models the setup of your project as you have outlined it in your previous posting. Now, if there's the usual dependency of gen on f/g, i.e. TARGET_LINK_LIBRARIES(gen f g), the generator would become out- of-date when f or g is touched, including simple RPATH changes, and this would result in the generator and the entire depending stuff being rebuilt. So, the job is to address gen's dependency on f/g. The dependency of gen on f/g is realised in an unusual manner: The libraries have a POST_BUILD custom command that copies the library files libf.so and libg.so to libf_gen.so and libg_gen.so, and gen is linked against these copies. Additionally, gen depends on the custom target gen_lib which (re)builds the libraries including their copies via "cmake --build". In this way, whenever gen is to be rebuilt, the libraries are rebuilt before - if necessary - and gen links against the updated libf_gen.so and libg_gen.so. Such a dependency is *not* tracked by CMake, so it might be dissolved without invalidating the generator target. This is done by reconfiguring the project while not taking the libraries' POST_BUILD custom commands into account anymore, i.e. a reconfiguration with -DRPATH=ON, cf. the IF(NOT RPATH)-ENDIF() constructs around the custom commands. Thereafter, lib{f,g}_gen.so are not updated along with lib{f,g}.so and accordingly, the generator with its file-level dependencies on solely the formers is not relinked, i.e. gen's dependency on f and g is removed without invalidating gen at the same time. Afterwards, you can change CMAKE_INSTALL_PREFIX and rebuild and you'll see that just lib{f,g}.so are relinked with the new RPATH's placeholders, but gen and especially main are left alone. A subsequent "make install" installs the project with lib{f,g}.so equipped with the final RPATH derived from CMAKE_INSTALL_PREFIX and without any rebuild operation, the issue you've complaint about in your initial posting. To crown it all, you have to link gen against lib{f,g}_gen.so using imported targets and their IMPORTED_LOCATION property; if you try to link against lib{f,g}_gen.so directly, the linker command will change from -L/-l combinations to relative paths when the project is switched to, say, RPATH mode, so gen's link.txt will be touched and gen relinked which is exactly to be prevented. Furthermore, the above-noted approach has some other drawbacks: While targets are not unnecessarily rebuilt, they are unnecessarily often checked for being out-of-date, but this should be a minor penalty compared to rather unnecessary rebuilds of considerable parts of the whole project. Additionally, after you've switched the project to RPATH mode by reconfiguring with -DRPATH=ON, a change in the source code or prerequisite targets of f/g wouldn't trigger a rebuild of gen, although this could be required in such a case - as I said before, you can't distinguish good from bad... ;) Finally, after switching back to, say, normal mode by -DRPATH=OFF, the targets are out-of-date, so a "make" will rebuild everything. Due to the latter point, I would recommend the following procedure: - Work on the project and build it until you are ready for installation. - Enable RPATH mode by "cmake . -DRPATH=ON -DCMAKE_INSTALL_PREFIX=...", rebuild the affected targets by "make" and install by "make install". - Set new installation prefix by "cmake . -DCMAKE_INSTALL_PREFIX=...", rebuild the affected targets by "make" and install by "make install". - Repeat the previous step for each installation you want to perform. - Reenable normal mode by "cmake . -DRPATH=OFF" to continue working on the project, but be aware of the imminent extensive rebuild. To my regret, I don't see any easy solution for your concern, but if the unnecessary rebuilds due to the the RPATH placeholder mechanism are a serious issue in your project, the above-noted approach can possibly be adapted to your needs. 'hope that helps. 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