On 07/07/2011 02:43 PM, Luke Dalessandro wrote:
> Hi Everyone,
> 
> I have the following build dependencies that I'm trying to implement in cmake.
> 
> The ultimate target of the build is an archive library, libme.a.
> 
> libme.a is composed of a number of static source files, (s1.cpp, ..., 
> sn.cpp), and one generated source file, (g.cpp).
> 
> g.cpp is built using a perl script that examines the object files associated 
> with S. For instance maybe it contains one string array with the names of all 
> of the symbols in the objects obtained with nm or objdump.
> 
> So traditionally, we have a build cycle that looks like:
> 
> compile s1.cpp -> s1.o
> ...
> compile sn.cpp -> sn.o
> perl getSymbols.pl s1.o ... sn.o -> g.cpp
> compile g.cpp -> g.o
> archive s1.o ... sn.o  g.o ->libme.a
> 
> I'm trying to emulate this with CMake. The only platform we have support for 
> the getSymbols.pl stuff is on Unix-based systems, in Windows we disable this 
> particular configuration.
> 
> My current plan is to have a library target libme.a that has the (s1.cpp, 
> ..., sn.cpp) as its sources, and a second library, libtemp.a, that has g.cpp 
> as a source. g.cpp is the output of a custom_command that depends on (s1.cpp, 
> ..., sn.cpp) and is built using getSymbols.pl (modified to account for the 
> fact that its input is a .a rather than the set of .os). Then I will add a 
> POST_BUILD custom_command for libtemp.a that extracts the object from 
> libtemp.a and adds it to the libme.a archive.
> 
> This has the advantage that g.cpp is compiled with all of the same flags as 
> the rest of the project---I'm not sure that there's a way to do this without 
> the libtemp intermediate target. I don't know how to add a PRE_LINK command 
> to libme.a that generates and compiles g.cpp in exactly the way that 
> everything else is compiled, and I can't add g.cpp as a generated source for 
> libme.a because I can't depend on the (s1.o, ..., sn.o) object files produced 
> in its compilation.
> 
> I'm worried that the dependency on the custom g.cpp isn't quite right because 
> I really depend on their object files. I could depend on libme.a, but that 
> seems like it will introduce a circular dependency since I update libme.a in 
> a POST_BUILD command for libtemp.a. I could also just say that 
> target_link_libraries(me temp) but I don't really want to expose the two 
> different libraries to users.
> 
> Does anyone know of a cleaner way to do this?
> 
> Luke

Look at the following exemplary project:

# CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(OBJDEP C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
FILE(WRITE ${CMAKE_BINARY_DIR}/s1.c "void s1(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/s2.c "void s2(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/s3.c "void s3(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/g.c "")  # Initially.
ADD_LIBRARY(me STATIC s1.c s2.c s3.c g.c)
SET_TARGET_PROPERTIES(me PROPERTIES
    RULE_LAUNCH_LINK "sh ${CMAKE_SOURCE_DIR}/objects.sh <OBJECTS> --")
ADD_CUSTOM_COMMAND(TARGET me POST_BUILD
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/g.cmake
    COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target me)

# objects.sh:
if [ "$1" != "--" ]; then
    OBJECTS=""
    while [ "$1" != "--" ]; do OBJECTS="${OBJECTS}$1\n"; shift; done
    echo -ne "${OBJECTS}" > objects.txt
fi
shift
exec $@

# g.cmake:
FILE(STRINGS objects.txt OBJECTS)
FILE(WRITE g.c.in "/*\n")
FOREACH(i IN LISTS OBJECTS)
    IF(NOT i MATCHES "^.*/g\\.c\\.[^/]*\$")
        FILE(APPEND g.c.in "${i}\n")
    ENDIF()
ENDFOREACH()
FILE(APPEND g.c.in "*/\n")
# Actually, use getSymbols.pl here.
CONFIGURE_FILE(g.c.in g.c COPYONLY)

First of all, the "me" target uses the objects.sh shell script as a
launcher at link time to collect the target's object files reliably;
since you said that your concern is limited to *nix, this shouldn't
be a serious restriction and is also not strictly needed. The check
for $1 equaling "--" is necessary since the script is called twice,
once for ar with object files and another time for ranlib without.

The g.cmake script is run as a POST_BUILD custom command for the "me"
target and uses the objects.txt file left by objects.sh to generate a
g.c.in template which is finally transferred to the g.c source file by
CONFIGURE_FILE(... COPYONLY). This is crucial because g.c must not be
touched if the list of object files has not changed, see below.

In the end, the POST_BUILD custom command rebuilds the "me" target via
CMake's --build switch. This means that the newly (re)generated g.c is
compiled and the "me" target relinked. Now, if the custom command does
not touch the g.c file - there's no reason to do so since nothing has
changed in the meantime - the "me" target's subsequent re-invocation
does nothing because all of the target's source and object files are
up-to-date; in particular, it doesn't invoke the custom command, so
the recursion terminates.

The downside of this approach is that the "me" target is sometimes
generated more than once - typically twice when the list of object
files, i.e. the g.c file, has changed - but this should be bearable.

'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

Reply via email to