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_PREFIX is used. If the
generated export files are deployed to the target, the workaround
will still be in place, and still be employed if required.
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();
};
Supports Markdown
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