[CMake] ExternalProject, target_link_libraries(), and Multi-configuration Builds.

Michael Hertling mhertling at online.de
Sun Oct 9 07:49:28 EDT 2011


On 10/09/2011 02:09 AM, michael lowell roberts wrote:
> On Sat, Oct 8, 2011 at 6:40 AM, Michael Hertling <mhertling at online.de>wrote:
> 
>> On 10/08/2011 05:33 AM, michael lowell roberts wrote:
>>> Hi all,
>>>
>>> I'm attempting to use the ExternalProject module to compile and link
>> against
>>> a library and I've run into a problem that I'm not certain how to
>> address.
>>> I'm using CMake 2.8.6 and Visual Studio 10 Express.
>>>
>>> The external project, in my case, is a CMake-compiled project and CMake
>>> predictably builds a matching configuration in the external project.
>>>
>>> The target_link_libraries() command, however, only allows for two
>>> configurations, at most, mapped to labels "debug" and "optimized."
>>>
>>> This allows for only two of the four default build configurations to
>>> complete successfully.
>>>
>>> For example, in my build scripts, I have told target_link_libraries() to
>> map
>>> "debug" configurations to the Debug version of library and optimized
>>> configurations map to the "RelWithDebInfo" build of the library.
>> Therefore,
>>> if I build the "Release" configuration, I get linker errors because the
>>> external project was also built with the "Release" configuration but I
>> need
>>> to link against "RelWithDebInfo."
>>>
>>> It seems to be that no matter how the target_link_library() mappings are
>> set
>>> up, only half of the default configurations will build properly because
>> of
>>> the dualism that target_link_libraries() uses.
>>>
>>> How do I get all four default build configurations working?
>>>
>>> Regards,
>>> Mike
>>
>> Could you boil down this issue to a minimal but self-contained
>> exemplary project and post it here for further investigation?
>>
> 
> Certainly.
> 
> I've attached a sample project that downloads and compiles the trio library,
> which can be found at the following site:
> 
> http://daniel.haxx.se/projects/trio/
> 
> It then attempts to link the library into a trivial executable that simply
> prints a message to the screen.
> 
> The build exhibits the problem I mentioned. Debug builds complete
> successfully. Release builds do not.

Okay, I was able to reproduce the issue. In fact, it is caused by your
manual mapping of configurations between your project and the external
project via TARGET_LINK_LIBRARIES()' debug/optimized keywords. However,
that's inappropriate anyways; you should use an imported library along
with its IMPORTED_LOCATION_<CONFIG> target properties instead. Look at
the attached trio.cmake file or the related diff, respectively. With
the new trio.cmake, I was able to build all configurations of the
exemplary project flawlessly, but please consider this just as a
hotfix, not a rock-solid solution.

> Additionally, the IDE appears incapable of determining when the build is
> up-to-date. Try to debug the executable to reproduce this problem. I'm
> inclined to believe that this is due to something I've done wrong and any
> help with this problem would also be appreciated.

I can't confirm this. When the test.c file ist touched, Visual Studio
recompiles it and relinkes the final executable as it should, and if
nothing has changed, nothing does happen. Could you provide further
information when the IDE does not behave as expected?

> Lastly, I'm certain that there are other problems I have not identified yet.
> If you could point out anything else that is obviously problematic, I would
> be grateful. Perhaps I am over-complicating the code, for example.

Hhm, yes, this might be the case... ;) Besides, there was a minor flaw
with include_directories(), see the diff, and constructions like

get_filename_component(TRIO_PREFIX "${TRIO_LIBRARY}" PATH)

doesn't seem to work well if TRIO_LIBRARY is something like

debug;.../lib/Debug/trio.lib;optimized;.../lib/RelWithDebInfo/trio.lib

AFAICS, the basic problem is that you need the trio library already
installed when your actual project is configured, and this can't be
done by a simple external project because the latter is completely
processed at build time, i.e. when your project's configuration is
already finished. For that reason, you need lines like

if(WIN32)
        set(TRIO_LIBRARY_NAME trio.lib)
else()
        set(TRIO_LIBRARY_NAME libtrio.a)
endif()

which is usually performed by CMake's FIND_LIBRARY() automatically.

IMO, possible solutions are:

- Integrate the external project's code base in your project's one,
  set it up appropriately and process it with an ADD_SUBDIRECTORY().
  However, in this way, you'll miss the external project's upstream.
- Apply the so-called super-build approach, i.e. provide a top-level
  CMakeLists.txt that pulls in the foreign project *and* your actual
  project as external projects with your project being the last one.
  In this manner, the foreign project is already build and possibly
  installed when your project is configured, so you can use CMake's
  FIND_*() commands to locate the foreign project's files. However,
  you must explicitly forward each variable that should be used in
  your project from the top-level CMakeLists.txt to your project's
  ExternalProject_Add() invocation, and there might also be issues
  w.r.t. the projects' common installation, see [1].

'hope that helps.

Regards,

Michael

[1] http://www.mail-archive.com/cmake@cmake.org/msg36170.html
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: trio.cmake
URL: <http://www.cmake.org/pipermail/cmake/attachments/20111009/4156ae58/attachment.asc>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: trio.cmake.diff
Type: text/x-diff
Size: 2100 bytes
Desc: not available
URL: <http://www.cmake.org/pipermail/cmake/attachments/20111009/4156ae58/attachment.diff>


More information about the CMake mailing list