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 usemingw32-make
command.) - CMake version: cmake 2.8.12.2.
- I tried to use result of the
make install
and theNo 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)
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).