[CMake] Problem building libraries with no sources with Visual Studio 9 (2008)

Michael Hertling mhertling at online.de
Thu Dec 23 00:44:13 EST 2010


On 12/22/2010 07:49 PM, Pere Mato Vila wrote:
>   AFAICS there are three different issues here:
> 
>  - Having a .def file as a source in a ADD_LIBRARY() it does the correct thing, which is using it to build the library, but it does not create a dependency to it. I would call this a bug.

For the nmake generator, this was asked in [1] two years ago but hasn't
received an answer; nevertheless, it seems to have been fixed recently
in [2]. However, I have no idea if it will work with the Visual Studio
generators and, as the case may be, why not. Perhaps due to the same
reason the upcoming LINK_DEPENDS property is limited to Makefiles?

> - The way to generate the .def file that I have figured out is perhaps not optimal and Bill Hoffman has provided me with a solution that exploits PRE_LINK option in  ADD_CUSTOM_COMMAND().

If I understand correctly, you need a dependency of ${library}.def on
${library}-static, and such a dependency can't be established by the
ADD_CUSTOM_COMMAND(TARGET ...) signature. In other words: A changed
${library}-static doesn't invalidate ${library}.def, so ${library}
isn't rebuilt despite the new dependency on .def files. See the
following example with an object file instead of a .def file:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(OBJECT C)
FILE(WRITE ${CMAKE_BINARY_DIR}/f.c "void f(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/f0.c "void f0(void){}\n")
EXECUTE_PROCESS(COMMAND cc -c f0.c)
ADD_LIBRARY(f SHARED f.c f0.o)
ADD_CUSTOM_COMMAND(TARGET f PRE_LINK COMMAND cc -c f0.c)

f0.o is compiled right before the library target is linked, but
touching f0.c - the prerequisite of f0.o - will entail nothing.

> - If I use ADD_LBRARY() with no real source files and only with a .def file does fail within the IDE (Visual Studio 9) and does work with nmake.

Just a spontaneous notion: On *nix, one can say

ADD_LIBRARY(f SHARED "" f.def)  # Note the "".
SET_TARGET_PROPERTIES(f PROPERTIES LINKER_LANGUAGE C)

In spite of f.def not being compilable such that there's no mediate
f.def <-- f dependency - that is what I actually meant with "CMake
does not know how to handle a .def file" - the target gets happily
built without object files, but I don't know if the Visual Studio
tools can be duped in this way.

Regards,

Michael

[1] http://www.mail-archive.com/cmake@cmake.org/msg17981.html
[2] http://public.kitware.com/Bug/view.php?id=11014

> On Dec 22, 2010, at 12:09 AM, Michael Hertling wrote:
> 
>> On 12/21/2010 08:45 PM, Bill Hoffman wrote:
>>> On 12/21/2010 2:17 PM, Michael Hertling wrote:
>>>
>>>> AFAIK, this is because CMake does not know how to handle a .def file
>>>> for incorporation in the target, i.e. ${library}.def has no LANGUAGE
>>>
>>> Actually, it should...
>>>
>>>
>>> Something like this should work:
>>> (assumes you have a perl script to create a .def file)
>>>
>>> cmake_minimum_required (VERSION 2.6)
>>> project (myexe)
>>>
>>> set (SOURCES mylib.cxx mylib2.cxx)
>>>
>>> # create a list of all the object files
>>> string (REGEX REPLACE "\\.cxx" ".obj" OBJECTS "${SOURCES}")
>>>
>>> # create a shared library with the .def file
>>> add_library (mylib SHARED ${SOURCES}
>>>   ${CMAKE_CURRENT_BINARY_DIR}/mylib.def
>>>   )
>>> # set the .def file as generated
>>> set_source_files_properties (
>>>   ${CMAKE_CURRENT_BINARY_DIR}/mylib.def
>>>   PROPERTIES GENERATED 1
>>>   )
>>>
>>> # create an executable
>>> add_executable (myexe myexe.cxx)
>>>
>>> # link the executable to the dll
>>> target_link_libraries(myexe mylib)
>>>
>>> #convert to windows slashes
>>> set (OUTDIR
>>>   ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
>>>   )
>>>
>>> string (REGEX REPLACE "/" "\\\\" OUTDIR ${OUTDIR})
>>>
>>> # create a custom pre link command that runs
>>> # a perl script to create a .def file using dumpbin
>>> add_custom_command (
>>>   TARGET mylib PRE_LINK
>>>   COMMAND perl
>>>   ARGS ${CMAKE_CURRENT_SOURCE_DIR}/makedef.pl
>>>   ${CMAKE_CURRENT_BINARY_DIR}\\mylib.def mylib
>>>   ${OUTDIR} ${OBJECTS} )
>>
>> Sorry, I haven't expressed myself precisely. My point is that mentioning
>> the .def file in the target's sources does not establish a dependency of
>> the target on the .def file, so the target isn't rebuilt when the .def
>> file has changed:
>>
>> CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
>> PROJECT(DEFS C)
>> FILE(WRITE ${CMAKE_BINARY_DIR}/f.c "void f(void){}\n")
>> FILE(WRITE ${CMAKE_BINARY_DIR}/f.def.in "")
>> ADD_CUSTOM_COMMAND(
>>    OUTPUT ${CMAKE_BINARY_DIR}/f1.def
>>    COMMAND ${CMAKE_COMMAND} -E
>>    copy ${CMAKE_BINARY_DIR}/f.def.in ${CMAKE_BINARY_DIR}/f1.def
>>    DEPENDS ${CMAKE_BINARY_DIR}/f.def.in
>> )
>> SET_SOURCE_FILES_PROPERTIES(
>>    ${CMAKE_BINARY_DIR}/f2.def PROPERTIES GENERATED TRUE
>> )
>> ADD_LIBRARY(f SHARED f.c f1.def f2.def)
>> ADD_CUSTOM_COMMAND(
>>    TARGET f
>>    PRE_LINK
>>    COMMAND ${CMAKE_COMMAND} -E copy
>>    ${CMAKE_BINARY_DIR}/f.def.in ${CMAKE_BINARY_DIR}/f2.def
>> )
>>
>> Touching f1.def or f2.def does not make the target rebuild, and touching
>> f.def.in just makes f1.def regenerate. It's touching f.c that results in
>> rebuilding the target due to the f.c <-- f.c.o <-- libf.so dependencies.
>> AFAIK, such a dependency does not exist between the target and the .def
>> files, or have I got you wrong?
>>
>> Regards,
>>
>> Michael


More information about the CMake mailing list