Commit 7521da28 authored by Stephen Kelly's avatar Stephen Kelly
Browse files

Introduce CMAKE_STAGING_PREFIX variable.

This variable can be useful in cross-compiling contexts where the
sysroot is read-only or where the sysroot should otherwise remain
pristine.

If the new CMAKE_STAGING_PREFIX variable is set, it is used instead
of CMAKE_INSTALL_PREFIX when generating the installation rules in
cmake_install.cmake.

This way, the CMAKE_INSTALL_PREFIX variable
always refers to the installation prefix on the target device, regardless
of whether host==target.

If any -rpath paths passed to the linker contain the CMAKE_STAGING_PREFIX,
the matching path fragments are replaced with the CMAKE_INSTALL_PREFIX.
Matching paths in the -rpath-link are not transformed.

The cross-prefix usr-move workaround is assumed not to require extension
regarding CMAKE_STAGING_PREFIX. The staging area is a single prefix, so
there is no scope for cross-prefix symlinks. The CMAKE_INSTALL_PREFIX
is still used to determine the workaround path, and that variable
remains the relevant one even if CMAKE_STAGING_PREFI...
parent e776a2da
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more
directories to be prepended to all other search directories. This
effectively "re-roots" the entire search under given locations. By
default it is empty.
effectively "re-roots" the entire search under given locations.
Paths which are descendants of the :variable:`CMAKE_STAGING_PREFIX` are excluded
from this re-rooting, because that variable is always a path on the host system.
By default the CMAKE_FIND_ROOT_PATH is empty.
The :variable:`CMAKE_SYSROOT` variable can also be used to specify exactly one
directory to use as a prefix. Setting :variable:`CMAKE_SYSROOT` also has other
......@@ -18,4 +20,4 @@ overridden on a per-call basis. By using CMAKE_FIND_ROOT_PATH_BOTH
the search order will be as described above. If
NO_CMAKE_FIND_ROOT_PATH is used then CMAKE_FIND_ROOT_PATH will not be
used. If ONLY_CMAKE_FIND_ROOT_PATH is used then only the re-rooted
directories will be searched.
directories and directories below :variable:`CMAKE_STAGING_PREFIX` will be searched.
......@@ -110,6 +110,7 @@ Variables that Change Behavior
/variable/CMAKE_PREFIX_PATH
/variable/CMAKE_PROGRAM_PATH
/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
/variable/CMAKE_STAGING_PREFIX
/variable/CMAKE_SYSTEM_IGNORE_PATH
/variable/CMAKE_SYSTEM_INCLUDE_PATH
/variable/CMAKE_SYSTEM_LIBRARY_PATH
......
......@@ -3,11 +3,13 @@ CMAKE_FIND_NO_INSTALL_PREFIX
Ignore the :variable:`CMAKE_INSTALL_PREFIX` when searching for assets.
CMake adds the :variable:`CMAKE_INSTALL_PREFIX` to the
CMake adds the :variable:`CMAKE_INSTALL_PREFIX` and the
:variable:`CMAKE_STAGING_PREFIX` variable to the
:variable:`CMAKE_SYSTEM_PREFIX_PATH` by default. This variable may be set
on the command line to control that behavior.
Set :variable:`CMAKE_FIND_NO_INSTALL_PREFIX` to TRUE to tell find_package not
to search in the :variable:`CMAKE_INSTALL_PREFIX` by default. Note that the
to search in the :variable:`CMAKE_INSTALL_PREFIX` or
:variable:`CMAKE_STAGING_PREFIX` by default. Note that the
prefix may still be searched for other reasons, such as being the same prefix
as the CMake installation, or for being a built-in system prefix.
CMAKE_STAGING_PREFIX
--------------------
This variable may be set to a path to install to when cross-compiling. This can
be useful if the path in :variable:`CMAKE_SYSROOT` is read-only, or otherwise
should remain pristine.
The CMAKE_STAGING_PREFIX location is also used as a search prefix by the ``find_*``
commands. This can be controlled by setting the :variable:`CMAKE_FIND_NO_INSTALL_PREFIX`
variable.
If any RPATH/RUNPATH entries passed to the linker contain the CMAKE_STAGING_PREFIX,
the matching path fragments are replaced with the :variable:`CMAKE_INSTALL_PREFIX`.
......@@ -9,8 +9,8 @@ appropriate subdirectories to the base directories. So FIND_PROGRAM()
adds /bin to each of the directories in the path, FIND_LIBRARY()
appends /lib to each of the directories, and FIND_PATH() and
FIND_FILE() append /include . By default this contains the standard
directories for the current system and the CMAKE_INSTALL_PREFIX. It
is NOT intended to be modified by the project, use CMAKE_PREFIX_PATH
for this. See also CMAKE_SYSTEM_INCLUDE_PATH,
directories for the current system, the CMAKE_INSTALL_PREFIX and
the :variable:`CMAKE_STAGING_PREFIX`. It is NOT intended to be modified by
the project, use CMAKE_PREFIX_PATH for this. See also CMAKE_SYSTEM_INCLUDE_PATH,
CMAKE_SYSTEM_LIBRARY_PATH, CMAKE_SYSTEM_PROGRAM_PATH, and
CMAKE_SYSTEM_IGNORE_PATH.
......@@ -43,6 +43,12 @@ if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
# Project install destination.
"${CMAKE_INSTALL_PREFIX}"
)
if(CMAKE_STAGING_PREFIX)
list(APPEND CMAKE_SYSTEM_PREFIX_PATH
# User-supplied staging prefix.
"${CMAKE_STAGING_PREFIX}"
)
endif()
endif()
# List common include file locations not under the common prefixes.
......
......@@ -79,6 +79,12 @@ if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
# Project install destination.
"${CMAKE_INSTALL_PREFIX}"
)
if (CMAKE_STAGING_PREFIX)
list(APPEND CMAKE_SYSTEM_PREFIX_PATH
# User-supplied staging prefix.
"${CMAKE_STAGING_PREFIX}"
)
endif()
endif()
if(CMAKE_CROSSCOMPILING AND NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
......@@ -94,6 +100,11 @@ if (NOT CMAKE_FIND_NO_INSTALL_PREFIX)
list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
"${CMAKE_INSTALL_PREFIX}/bin"
)
if (CMAKE_STAGING_PREFIX)
list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
"${CMAKE_STAGING_PREFIX}/bin"
)
endif()
endif()
list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
"${_CMAKE_INSTALL_DIR}/bin"
......
......@@ -1902,6 +1902,10 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
if(use_build_rpath || use_link_rpath)
{
std::string rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
const char *stagePath
= this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
const char *installPrefix
= this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
cmSystemTools::ConvertToUnixSlashes(rootPath);
std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
for(std::vector<std::string>::const_iterator ri = rdirs.begin();
......@@ -1916,6 +1920,14 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
{
d = d.substr(rootPath.size());
}
else if (stagePath && *stagePath && d.find(stagePath) == 0)
{
std::string suffix = d.substr(strlen(stagePath));
d = installPrefix;
d += "/";
d += suffix;
cmSystemTools::ConvertToUnixSlashes(d);
}
if(emitted.insert(d).second)
{
runtimeDirs.push_back(d);
......@@ -1936,6 +1948,14 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
{
d = d.substr(rootPath.size());
}
else if (stagePath && *stagePath && d.find(stagePath) == 0)
{
std::string suffix = d.substr(strlen(stagePath));
d = installPrefix;
d += "/";
d += suffix;
cmSystemTools::ConvertToUnixSlashes(d);
}
if(emitted.insert(d).second)
{
runtimeDirs.push_back(d);
......
......@@ -165,6 +165,9 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
cmSystemTools::ConvertToUnixSlashes(*ri);
}
const char* stagePrefix =
this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
// Copy the original set of unrooted paths.
std::vector<std::string> unrootedPaths = paths;
paths.clear();
......@@ -179,7 +182,9 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
// already inside. Skip the unrooted path if it is relative to
// a user home directory or is empty.
std::string rootedDir;
if(cmSystemTools::IsSubDirectory(ui->c_str(), ri->c_str()))
if(cmSystemTools::IsSubDirectory(ui->c_str(), ri->c_str())
|| (stagePrefix
&& cmSystemTools::IsSubDirectory(ui->c_str(), stagePrefix)))
{
rootedDir = *ui;
}
......
......@@ -370,6 +370,11 @@ void cmLocalGenerator::GenerateInstallRules()
prefix = "/usr/local";
}
#endif
if (const char *stagingPrefix
= this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX"))
{
prefix = stagingPrefix;
}
// Compute the set of configurations.
std::vector<std::string> configurationTypes;
......
......@@ -269,6 +269,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(CompileOptions CompileOptions)
ADD_TEST_MACRO(CompatibleInterface CompatibleInterface)
ADD_TEST_MACRO(AliasTarget AliasTarget)
ADD_TEST_MACRO(StagingPrefix StagingPrefix)
ADD_TEST_MACRO(InterfaceLibrary InterfaceLibrary)
set_tests_properties(EmptyLibrary PROPERTIES
PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test")
......
cmake_minimum_required(VERSION 2.8.12)
project(StagingPrefix)
# Wipe out the install tree
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/CleanupProject
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ConsumerBuild
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ProducerBuild
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/stage
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/prefix
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ignored
)
add_custom_target(CleanupTarget ALL DEPENDS ${CMAKE_BINARY_DIR}/CleanupProject)
set_property(
SOURCE ${CMAKE_BINARY_DIR}/CleanupProject
PROPERTY SYMBOLIC 1
)
if(CMAKE_CONFIGURATION_TYPES)
set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
else()
if(CMAKE_BUILD_TYPE)
set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
else()
set(NESTED_CONFIG_TYPE)
endif()
endif()
# Build and install the producer.
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/ProducerProject
COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
--build-and-test
${CMAKE_SOURCE_DIR}/Producer
${CMAKE_BINARY_DIR}/ProducerBuild
--build-noclean
--build-project Producer
--build-target install
--build-generator ${CMAKE_GENERATOR}
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
--build-options
-DCMAKE_VERBOSE_MAKEFILE=1
"-DCMAKE_STAGING_PREFIX=${CMAKE_BINARY_DIR}/stage"
"-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/prefix"
VERBATIM
)
add_custom_target(ProducerTarget ALL DEPENDS ${CMAKE_BINARY_DIR}/ProducerProject)
add_dependencies(ProducerTarget CleanupTarget)
set_property(
SOURCE ${CMAKE_BINARY_DIR}/ProducerProject
PROPERTY SYMBOLIC 1
)
if(NOT WIN32)
file(WRITE
"${CMAKE_BINARY_DIR}/ignored/${CMAKE_BINARY_DIR}/stage/include/ignored.h"
"#define IGNORED\n"
)
endif()
# Build and install the consumer.
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/ConsumerProject
COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
--build-and-test
${CMAKE_SOURCE_DIR}/Consumer
${CMAKE_BINARY_DIR}/ConsumerBuild
--build-noclean
--build-project Consumer
--build-target install
--build-generator ${CMAKE_GENERATOR}
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
--build-options
"-DCMAKE_FIND_ROOT_PATH=${CMAKE_BINARY_DIR}/ignored"
"-DCMAKE_STAGING_PREFIX=${CMAKE_BINARY_DIR}/stage"
-DCMAKE_VERBOSE_MAKEFILE=1
VERBATIM
)
add_custom_target(ConsumerTarget ALL DEPENDS ${CMAKE_BINARY_DIR}/ConsumerProject)
add_dependencies(ConsumerTarget ProducerTarget)
set_property(
SOURCE ${CMAKE_BINARY_DIR}/ConsumerProject
PROPERTY SYMBOLIC 1
)
add_executable(StagingPrefix main.cpp)
add_dependencies(StagingPrefix ConsumerTarget)
cmake_minimum_required (VERSION 2.8.12)
project(Consumer)
add_executable(executable main.cpp)
find_package(Foo CONFIG REQUIRED)
target_link_libraries(executable Foo::foo)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(Bar MODULE REQUIRED)
include_directories(${Bar_INCLUDE_DIRS})
target_link_libraries(executable ${Bar_LIBRARIES})
install(TARGETS executable DESTINATION bin)
if(NOT WIN32)
find_path(IGNORED_INCLUDE_DIR ignored.h)
if (IGNORED_INCLUDE_DIR)
message(SEND_ERROR "Should not find this file. The search path should be excluded.")
endif()
endif()
find_path(_inc_prefix bar.h PATH_SUFFIXES bar)
set(Bar_INCLUDE_DIRS ${_inc_prefix})
find_library(Bar_LIBRARY bar)
set(Bar_LIBRARIES ${Bar_LIBRARY})
#include "foo.h"
#include "bar.h"
int main(int, char **)
{
Foo f;
Bar b;
return f.foo() + b.bar();
}
cmake_minimum_required (VERSION 2.8.12)
project(Producer)
add_library(foo SHARED foo.cpp)
install(TARGETS foo EXPORT fooTargets
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
INCLUDES DESTINATION include/foo
)
install(FILES foo.h DESTINATION include/foo)
install(EXPORT fooTargets
FILE FooConfig.cmake
NAMESPACE Foo::
DESTINATION lib/cmake/Foo
)
add_library(bar SHARED bar.cpp)
install(TARGETS bar
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install(FILES bar.h DESTINATION include/bar)
#include "bar.h"
int Bar::bar()
{
return 0;
}
class
#ifdef _WIN32
__declspec(dllexport)
#endif
Bar
{
public:
int bar();
};
#include "foo.h"
int Foo::foo()
{
return 0;
}
class
#ifdef _WIN32
__declspec(dllexport)
#endif
Foo
{
public:
int foo();
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment