[CMake] Package installation conundrum

Michael Wild themiwi at gmail.com
Wed May 9 02:07:24 EDT 2012


On 05/08/2012 11:13 PM, Dave Abrahams wrote:
> 
> on Tue May 08 2012, Alexander Neundorf <a.neundorf-work-hi6Y0CQ0nG0-AT-public.gmane.org> wrote:
> 
>> On Tuesday 08 May 2012, Dave Abrahams wrote:
>>
>>> Here's another one!
>>>
>>> Scenario:
>>>
>>> * I am running CMake under 0install to build and install libraries
>>>
>>> * Each library builds a package SomePackage for the library binaries
>>> and another package SomePackage-dev for the library headers (and
>>> import libraries on Windows)
>>>
>>> * The FindSomePackage.cmake file is part of the -dev package
>>>
>>> * After building, 0install moves each package's build products into a
>>> mostly-unpredictable subdirectory of its otherwise-read-only "cache"
>>> (~/.cache/0install.net/). The subdirectory's name is determined by a
>>> hash of the files.
>>>
>>> * To get this working, I followed the scheme discussed here:
>>>
>>> http://news.gmane.org/find-root.php?message_id=%3cm2lil6s8jq.fsf%40pluto.l
>>> uannocracy.com%3e
>>>
>>> Summary:
>>>
>>> 1. Create a 0install "SomePackage-preinstall" package. Building this
>>> package involves CMake building and installing both SomePackage and
>>> SomePackage-dev into separate subdirectories (main/ and dev/) of
>>> some prefix. 0install thereafter moves the whole directory tree
>>> into its cache in a directory called sha1=someuglyhash
>>>
>>> 2. SomePackage's 0installation procedure is to copy
>>> sha1=someuglyhash/main/ into its distribution directory (which then ends
>>> up in
>>> ~/.cache/0install.net/sha1=otheruglyhash)
>>>
>>> 3. SomePackage-dev's 0installation procedure is to copy
>>> sha1=someuglyhash/dev/ into its distribution directory
>>>
>>> Problem: FindSomePackageConfig.cmake now has the wrong path to the
>>> library binaries.
>>>
>>> Any help most appreciated.
>>
>> Can you please summarize what you actually want to achieve ?
> 
> Well, I tried to, above.
> 
> In short, I want to create separate main and -dev packages without
> building twice, under the constraints imposed by 0install.
> 
>> Do you say that libFoo installs a FindFoo.cmake as part of libFoo-devel ?
>>
>> If that's the case, then this is wrong.
> 
> I'm sorry, that *is* wrong.  It installs a FooConfig.cmake as part of libFoo.devel
> 
>> FindFoo.cmake must be part of the using software, not of the software to be
>> searched.
>>
>> Why do you have to find the installed library in this cache directory
>> ?
> 
> Because, in a 0install world, that's where things go when you "install"
> them.
> 


Ok, how you do it along these lines:

CMakeLists.txt:
#-------------- BOF

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Foo)

set(FOO_VERSION 1.2.3)

# initialize (absolute) installation directory variables
set(INSTALL_BIN_DIR bin CACHE PATH "Install path for binaries")
set(INSTALL_LIB_DIR lib CACHE PATH "Install path for libraries")
set(INSTALL_INCLUDE_DIR include CACHE PATH "Install path for headers")
# this is for UNIX systems, see docs of find_package() for the search
# paths on APPLE and WIN32
set(INSTALL_CMAKE_DIR lib/foo-${FOO_VERSION}/cmake CACHE PATH
  "Install path for CMake files")
foreach(t BIN LIB INCLUDE CMAKE)
  if(NOT IS_ABSOLUTE ${INSTALL_${t}_DIR})
    set(INSTALL_${t}_DIR ${CMAKE_INSTALL_PREFIX}/${INSTALL_${t}_DIR})
  endif()
  mark_as_advanced(INSTALL_${t}_DIR)
endforeach()

# configure FooConfig.cmake and friends. FooConfig.cmake must be able
# to locate FooExports.cmake and FOO_INCLUDE_DIR relative to its own
# directory without using absolute paths.
configure_file(cmake/FooConfig.cmake.in
  ${PROJECT_BINARY_DIR}/FooConfig.cmake @ONLY)
configure_file(cmake/FooConfigVersion.cmake.in
  ${PROJECT_BINARY_DIR}/FooConfigVersion.cmake @ONLY)

# configure the headers into the build tree so the package can be used
# without installing it and not hard-coding the source/build directory
# information into FooConfig.cmake
configure_file(include/foo.h
  ${PROJECT_BINARY_DIR}/include/foo.h COPYONLY)

# build targets
add_library(foo src/foo.cpp include/foo.h)
set_target_properties(foo PROPERTIES
  PUBLIC_HEADER include/foo.h
  VERSION ${FOO_VERSION}
  SOVERSION 1.0)
add_executable(bar bar.cpp)
target_link_libraries(bar foo)

# install targets and files
install(TARGETS foo bar
  EXPORT FooExports
  RUNTIME DESTINATION ${INSTALL_BIN_DIR} COMPONENT bin
  LIBRARY DESTINATION ${INSTALL_LIB_DIR} COMPONENT bin
  ARCHIVE DESTINATION ${INSTALL_LIB_DIR} COMPONENT dev
  PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT dev)

install(FILES
  ${PROJECT_BINARY_DIR}/FooConfig.cmake
  ${PROJECT_BINARY_DIR}/FooConfigVersion.cmake
  DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT dev)

# export targets to build and install tree
export(TARGETS foo bar NAMESPACE Foo_
  FILE ${PROJECT_BINARY_DIR}/FooExports.cmake)
export(PACKAGE Foo)

install(EXPORT FooExports
  DESTINATION ${INSTALL_CMAKE_DIR}
  NAMESPACE Foo_
  COMPONENT dev)

#-------------- EOF


With such a setup, you do something like the following for the
installation into the cache directories:

mkdir /path/to/build-tree
cd /path/to/build-tree
cmake /path/to/source-tree
make
DESTDIR=/path/to/bin-cache cmake -DCOMPONENT=bin -P cmake_install.cmake
DESTDIR=/path/to/dev-cache cmake -DCOMPONENT=dev -P cmake_install.cmake


Note that the -D options must be *before*the -P option, otherwise the
definitions will not be passed to the cmake_install.cmake script.

Now you have everything installed into different cache directories, but
still containing correct path information for the final installation
that is to be performed by 0install.


More information about the CMake mailing list