CPack: How to use exporting to create library package? Missing *Targets-noconfig.cmake file

血红的双手。 提交于 2020-01-04 01:52:31

问题


Update

It looks like it's Windows cpack version bug - under Linux (Ubuntu) the cpack command the missing file. I'll do more research and post results when I have more time.


Note: I completely changed this question because I was able to simplify it and create new, shorter example. Core problem, however didn't change in the slightest.

Problem description

I have a library project, let's call it Foo, which I pack using cpack command. This package contains FooConfig.cmake and FooTargets.cmake files (the second one exported by cmake mechanisms). Problem is, that this is not enough for cmake to use it. find_package() finds it, but when linking with foo, No rule to make target foo-NOTFOUND', needed by bar.exe'. Stop. error appears.

But if I install it with make install DESTDIR=./out_dir, it works and it contains one more file: FooTargets-noconfig.cmake. This file contains path to the foo library file.

So, what I need to do to fix this? Is there a document describing this behavior?

Bonus question: I see that the *-noconfig* file contains path to the library, but not to headers directory. Is there a way how to configure library project so this generated file will contain it automatically, too?

More info, notes:

  • My OS: Windows 7, 64 bit.
  • Compiler: MinGW 4.4.0 (32 bit). (Note: yes, instead of make I use mingw32-make command.)
  • CMake version: cmake 2.8.12.2.
  • I tried to use result of the make install and the No rule to make target xyz-NOTFOUND', needed by Index.exe'. Stop. error disappeared, everything compiled and result exe was working as expected. It looks like the noconfig file is all what is needed.

Workflow / reproduce steps:

  • After created the code (see bellow):
  • cmake-gui to create build directory (library project) (Configure, then Generate)
  • mingw32-make in build directory
  • variant a) mingw32-make install DESTDIR=./out_dir to install the library
  • variant b) cpack -C CpackConfig.cmake -G ZIP to get package with the library
  • use files from previous step and move it to special directory which is in CMAKE_PREFIX_PATH environment variable so the cmake can find it (note "move", not "copy" so the original files are removed).
  • cmake-gui for executable project (again, Configure, then Generate)
  • mingw32-make in build directory

Last step is different for variant a) and b). For a), build finishes and executable works normally, as expected. In case of b), error No rule to make target xyz-NOTFOUND', needed by Index.exe'. Stop. appears with no more information.

My example code:

- Foo/                          (Experimental library)
  - CMakeLists.txt              (XyzLib configuration)
  - foo.cpp                     (Function implementation - just prints something)
  - foo.h                       (Contains just single function)
  - FooConfig.cmake             (Configuration so the find_package find the
                                 library)
- Bar/                          (Testing executable)
  - CMakeLists.txt              (Executable configuration)
  - bar.cpp                     (Main function printing something and
                                 calling the Foo library function)

Foo/CMakeLists.txt :

cmake_minimum_required(VERSION 2.6.3)
project("Foo")

add_library(foo STATIC foo.h foo.cpp)

set_target_properties(foo PROPERTIES PUBLIC_HEADER foo.h)

install(TARGETS foo EXPORT fooTargets
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
        PUBLIC_HEADER DESTINATION include
        INCLUDES DESTINATION include)

install(FILES FooConfig.cmake DESTINATION lib/foo)

install(EXPORT fooTargets FILE "FooTargets.cmake" DESTINATION lib/foo)

include(CPack)

Foo/foo.cpp :

#include <iostream>

#include "foo.h"

void FooCall()
{
    ::std::cout << "Hello from Foo!" << ::std::endl;
}

Foo/foo.h :

#ifndef FOO_H
#define FOO_H

void FooCall();

#endif // FOO_H

Foo/FooConfig.cmake :

# - Config file for the Foo library package
# This module defines the following variables:
#  Foo_FOUND         - true if this module was found, false otherwise
#  Foo_INCLUDE_DIRS  - include directories
#  Foo_LIBRARIES     - libraries to link against

get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)

# Import targets
include("${SELF_DIR}/FooTargets.cmake")

# Foo_INCLUDE_DIRS
get_filename_component(Foo_INCLUDE_DIRS "${SELF_DIR}/../../include" ABSOLUTE)

# Foo_LIBRARIES
set(Foo_LIBRARIES foo)

Bar/CMakeLists.txt :

cmake_minimum_required(VERSION 2.6.3)
project("Bar")

add_executable(bar bar.cpp)

find_package(Foo REQUIRED)
include_directories(${Foo_INCLUDE_DIRS})
target_link_libraries(bar ${Foo_LIBRARIES})

Bar/bar.cpp

#include <iostream>

#include "foo.h"

int main(int argc, char *argv[])
{
    ::std::cout << "Hello from bar!" << ::std::endl;
    FooCall();
    return 0;
}

Some generated files:

For case you're interested, there are few generated files:

lib/foo/FooTargets-noconfig.cmake

#----------------------------------------------------------------
# Generated CMake target import file for configuration "".
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

# Import target "foo" for configuration ""
set_property(TARGET foo APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
set_target_properties(foo PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "CXX"
  IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libfoo.a"
  )

list(APPEND _IMPORT_CHECK_TARGETS foo )
list(APPEND _IMPORT_CHECK_FILES_FOR_foo "${_IMPORT_PREFIX}/lib/libfoo.a" )

# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

lib/foo/FooTargets.cmake

# Generated by CMake 2.8.12.2

if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
   message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget foo)
  list(APPEND _expectedTargets ${_expectedTarget})
  if(NOT TARGET ${_expectedTarget})
    list(APPEND _targetsNotDefined ${_expectedTarget})
  endif()
  if(TARGET ${_expectedTarget})
    list(APPEND _targetsDefined ${_expectedTarget})
  endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
  set(CMAKE_IMPORT_FILE_VERSION)
  cmake_policy(POP)
  return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
  message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)


# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)

# Create imported target foo
add_library(foo STATIC IMPORTED)

set_target_properties(foo PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)

# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/FooTargets-*.cmake")
foreach(f ${CONFIG_FILES})
  include(${f})
endforeach()

# Cleanup temporary variables.
set(_IMPORT_PREFIX)

# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
  foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
    if(NOT EXISTS "${file}" )
      message(FATAL_ERROR "The imported target \"${target}\" references the file
   \"${file}\"
but this file does not exist.  Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
   \"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
    endif()
  endforeach()
  unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)

# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.

# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

回答1:


Use the export command to create exported targets for use from the build directory:

http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages

CMake 2.8.12 does not support export(EXPORT), but does support export(TARGETS).



来源:https://stackoverflow.com/questions/23672672/cpack-how-to-use-exporting-to-create-library-package-missing-targets-noconfig

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!