[CMake] Reverse dependencies (Unix Makefiles)

Michael Hertling mhertling at online.de
Wed May 26 11:17:17 EDT 2010


On 05/26/2010 12:31 PM, Jesper Eskilson wrote:
> On 05/25/2010 05:35 PM, Michael Hertling wrote:
>> On 05/25/2010 03:58 PM, Jesper Eskilson wrote:
>>> On 05/25/2010 02:41 PM, Michael Hertling wrote:
>>>
>>>> Exactly: The need for A's repetition in the link line is a sole affair
>>>> of A and C. Therefore, IMO, it should not be brought explicitly to D's
>>>> link line whereas an approach with two TARGET_LINK_LIBRARIES() for the
>>>> A'n'C circular dependency and one for D against A would express the
>>>> actual relations quite accurately.
>>>
>>> Can CMake express this for IMPORTED libraries as well. Both A, B, and C
>>> in this case are (or can be) IMPORTED libraries, and
>>> TARGET_LINK_LIBRARIES() fail if the first argument is an IMPORTED library.
>>>
>>> Until I can figure out how to do that, I'll have to go with repeating A
>>> on D's link line.
>>
>> Look at the following CMakeLists.txt:
>>
>> CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
>> PROJECT(ICD C)
>> # Generate circular dependent static libraries:
>> FILE(WRITE A.c "void fA(void){ fC(); } void ident(void){}")
>> FILE(WRITE C.c "void fC(void){ ident(); }")
>> ADD_LIBRARY(A0 STATIC EXCLUDE_FROM_ALL A.c)
>> ADD_LIBRARY(C0 STATIC EXCLUDE_FROM_ALL C.c)
>> SET_TARGET_PROPERTIES(A0 PROPERTIES ARCHIVE_OUTPUT_NAME A)
>> SET_TARGET_PROPERTIES(C0 PROPERTIES ARCHIVE_OUTPUT_NAME C)
>> # Incorporate them as imported targets:
>> ADD_LIBRARY(A STATIC IMPORTED)
>> ADD_LIBRARY(C STATIC IMPORTED)
>> SET_TARGET_PROPERTIES(A PROPERTIES IMPORTED_LOCATION
>> ${CMAKE_CURRENT_BINARY_DIR}/libA.a)
>> SET_TARGET_PROPERTIES(C PROPERTIES IMPORTED_LOCATION
>> ${CMAKE_CURRENT_BINARY_DIR}/libC.a)
>> # Declare their circular dependency:
>> SET_TARGET_PROPERTIES(A PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES C)
>> SET_TARGET_PROPERTIES(C PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES A)
>> # Executable D linking against library A:
>> FILE(WRITE D.c "void main(void){ fA(); }")
>> ADD_EXECUTABLE(D D.c)
>> TARGET_LINK_LIBRARIES(D A)
>>
>> After CMaking, type "make A0 C0" to build the circular dependent
>> libA.a and libC.a, and then "make VERBOSE=1"; the link line is:
>>
>> gcc CMakeFiles/D.dir/D.c.o -o D -rdynamic libA.a libC.a libA.a libC.a
>>
>> The target property IMPORTED_LINK_INTERFACE_LIBRARIES seems to make it.
> 
> Will this still work with an executable E wich depends on B -> C -> B. 
> Won't C pull in A as well?

OK, I suppose, that means you have targets D *and* E in your project, D
links against A, E against B, A and B both link against C which finally
needs A *or* B, right? ['fetching a cup of coffee... ;) ]

Now, indeed, you can not associate C with A in this exclusive manner
anymore, but you can make use of an imported target's decoupling from
its actual file: Introduce two imported library targets CA and CB, both
pointing to libC.a on disk, but associated with either A or B. Look here:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(ABCDE C)
# Generate static libraries A,B,C with circular dependencies:
FILE(WRITE A.c "void fA(void){ fC(); } void ident(void){}")
FILE(WRITE B.c "void fB(void){ fC(); } void ident(void){}")
FILE(WRITE C.c "void fC(void){ ident(); }")
ADD_LIBRARY(A0 STATIC EXCLUDE_FROM_ALL A.c)
ADD_LIBRARY(B0 STATIC EXCLUDE_FROM_ALL B.c)
ADD_LIBRARY(C0 STATIC EXCLUDE_FROM_ALL C.c)
SET_TARGET_PROPERTIES(A0 PROPERTIES ARCHIVE_OUTPUT_NAME A)
SET_TARGET_PROPERTIES(B0 PROPERTIES ARCHIVE_OUTPUT_NAME B)
SET_TARGET_PROPERTIES(C0 PROPERTIES ARCHIVE_OUTPUT_NAME C)
# Incorporate A and B as imported targets:
ADD_LIBRARY(A STATIC IMPORTED)
ADD_LIBRARY(B STATIC IMPORTED)
SET_TARGET_PROPERTIES(A PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_BINARY_DIR}/libA.a)
SET_TARGET_PROPERTIES(B PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_BINARY_DIR}/libB.a)
# Incorporate two imported targets CA and CB for C:
ADD_LIBRARY(CA STATIC IMPORTED)
ADD_LIBRARY(CB STATIC IMPORTED)
SET_TARGET_PROPERTIES(CA PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_BINARY_DIR}/libC.a)
SET_TARGET_PROPERTIES(CB PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_BINARY_DIR}/libC.a)
# Declare circular dependencies:
SET_TARGET_PROPERTIES(A PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES CA)
SET_TARGET_PROPERTIES(CA PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES A)
SET_TARGET_PROPERTIES(B PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES CB)
SET_TARGET_PROPERTIES(CB PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES B)
# Generate executable D linking against library A:
FILE(WRITE D.c "void main(void){ fA(); }")
ADD_EXECUTABLE(D D.c)
TARGET_LINK_LIBRARIES(D A)
# Generate executable E linking against library B:
FILE(WRITE E.c "void main(void){ fB(); }")
ADD_EXECUTABLE(E E.c)
TARGET_LINK_LIBRARIES(E B)

After cmaking, type "make {A,B,C}0" to build lib{A,B,C}.a, and then
"make VERBOSE=1" for the executables D and E; the link lines are:

gcc CMakeFiles/D.dir/D.c.o -o D -rdynamic libA.a libC.a libA.a libC.a
gcc CMakeFiles/E.dir/E.c.o -o E -rdynamic libB.a libC.a libB.a libC.a

Thus, the circular dependencies are respected as desired without
repeating A or B in TARGET_LINK_LIBRARIES() for D and E.

Regards,

Michael


More information about the CMake mailing list