Link libraries by full path even in implicit directories
When CMP0003 was first introduced we wanted to link all libraries by full path. However, some projects had problems on platforms where find_library would find /usr/lib/libfoo.so when the project really wanted to link to /usr/lib/<arch>/libfoo.so and had been working by accident because pre-CMP0003 behavior used -lfoo to link. We first tried to address that in commit v2.6.0~440 (Teach find_library to avoid returning library paths in system directories, 2008-01-23) by returning just "foo" for libraries in implicit link directories. This caused problems for projects expecting find_library to always return a full path. We ended up using the solution in commit v2.6.0~366 (... switch library paths found in implicit link directories to use -l, 2008-01-31). However, the special case for libraries in implicit link directories has also proven problematic and confusing. Introduce policy CMP0060 to switch to linking all libraries by full path even if they are in implicit link directories. Explain in the policy documentation the factors that led to the original approach and now to this approach.
This commit is contained in:
parent
318cd37097
commit
882f48e5ba
|
@ -34,14 +34,20 @@ Each ``<item>`` may be:
|
||||||
automatically be added in the build system to make sure the named
|
automatically be added in the build system to make sure the named
|
||||||
library target is up-to-date before the ``<target>`` links.
|
library target is up-to-date before the ``<target>`` links.
|
||||||
|
|
||||||
|
If an imported library has the :prop_tgt:`IMPORTED_NO_SONAME`
|
||||||
|
target property set, CMake may ask the linker to search for
|
||||||
|
the library instead of using the full path
|
||||||
|
(e.g. ``/usr/lib/libfoo.so`` becomes ``-lfoo``).
|
||||||
|
|
||||||
* **A full path to a library file**: The generated link line will
|
* **A full path to a library file**: The generated link line will
|
||||||
normally preserve the full path to the file. However, there are
|
normally preserve the full path to the file. The buildsystem will
|
||||||
some cases where CMake must ask the linker to search for the library
|
|
||||||
(e.g. ``/usr/lib/libfoo.so`` becomes ``-lfoo``), such as when it
|
|
||||||
appears in a system library directory that the compiler front-end
|
|
||||||
may replace with an alternative. Either way, the buildsystem will
|
|
||||||
have a dependency to re-link ``<target>`` if the library file changes.
|
have a dependency to re-link ``<target>`` if the library file changes.
|
||||||
|
|
||||||
|
There are some cases where CMake may ask the linker to search for
|
||||||
|
the library (e.g. ``/usr/lib/libfoo.so`` becomes ``-lfoo``), such
|
||||||
|
as when a shared library is detected to have no ``SONAME`` field.
|
||||||
|
See policy :policy:`CMP0060` for discussion of another case.
|
||||||
|
|
||||||
If the library file is in a Mac OSX framework, the ``Headers`` directory
|
If the library file is in a Mac OSX framework, the ``Headers`` directory
|
||||||
of the framework will also be processed as a
|
of the framework will also be processed as a
|
||||||
:ref:`usage requirement <Target Usage Requirements>`. This has the same
|
:ref:`usage requirement <Target Usage Requirements>`. This has the same
|
||||||
|
|
|
@ -117,3 +117,4 @@ All Policies
|
||||||
/policy/CMP0057
|
/policy/CMP0057
|
||||||
/policy/CMP0058
|
/policy/CMP0058
|
||||||
/policy/CMP0059
|
/policy/CMP0059
|
||||||
|
/policy/CMP0060
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
CMP0060
|
||||||
|
-------
|
||||||
|
|
||||||
|
Link libraries by full path even in implicit directories.
|
||||||
|
|
||||||
|
Policy :policy:`CMP0003` was introduced with the intention of always
|
||||||
|
linking library files by full path when a full path is given to the
|
||||||
|
:command:`target_link_libraries` command. However, on some platforms
|
||||||
|
(e.g. HP-UX) the compiler front-end adds alternative library search paths
|
||||||
|
for the current architecture (e.g. ``/usr/lib/<arch>`` has alternatives
|
||||||
|
to libraries in ``/usr/lib`` for the current architecture).
|
||||||
|
On such platforms the :command:`find_library` may find a library such as
|
||||||
|
``/usr/lib/libfoo.so`` that does not belong to the current architecture.
|
||||||
|
|
||||||
|
Prior to policy :policy:`CMP0003` projects would still build in such
|
||||||
|
cases because the incorrect library path would be converted to ``-lfoo``
|
||||||
|
on the link line and the linker would find the proper library in the
|
||||||
|
arch-specific search path provided by the compiler front-end implicitly.
|
||||||
|
At the time we chose to remain compatible with such projects by always
|
||||||
|
converting library files found in implicit link directories to ``-lfoo``
|
||||||
|
flags to ask the linker to search for them. This approach allowed existing
|
||||||
|
projects to continue to build while still linking to libraries outside
|
||||||
|
implicit link directories via full path (such as those in the build tree).
|
||||||
|
|
||||||
|
CMake does allow projects to override this behavior by using an
|
||||||
|
:ref:`IMPORTED library target <Imported Targets>` with its
|
||||||
|
:prop_tgt:`IMPORTED_LOCATION` property set to the desired full path to
|
||||||
|
a library file. In fact, many :ref:`Find Modules` are learning to provide
|
||||||
|
:ref:`Imported Targets` instead of just the traditional ``Foo_LIBRARIES``
|
||||||
|
variable listing library files. However, this makes the link line
|
||||||
|
generated for a library found by a Find Module depend on whether it
|
||||||
|
is linked through an imported target or not, which is inconsistent.
|
||||||
|
Furthermore, this behavior has been a source of confusion because the
|
||||||
|
generated link line for a library file depends on its location. It is
|
||||||
|
also problematic for projects trying to link statically because flags
|
||||||
|
like ``-Wl,-Bstatic -lfoo -Wl,-Bdynamic`` may be used to help the linker
|
||||||
|
select ``libfoo.a`` instead of ``libfoo.so`` but then leak dynamic linking
|
||||||
|
to following libraries. (See the :prop_tgt:`LINK_SEARCH_END_STATIC`
|
||||||
|
target property for a solution typically used for that problem.)
|
||||||
|
|
||||||
|
When the special case for libraries in implicit link directories was first
|
||||||
|
introduced the list of implicit link directories was simply hard-coded
|
||||||
|
(e.g. ``/lib``, ``/usr/lib``, and a few others). Since that time, CMake
|
||||||
|
has learned to detect the implicit link directories used by the compiler
|
||||||
|
front-end. If necessary, the :command:`find_library` command could be
|
||||||
|
taught to use this information to help find libraries of the proper
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
For these reasons, CMake 3.3 and above prefer to drop the special case
|
||||||
|
and link libraries by full path even when they are in implicit link
|
||||||
|
directories. Policy ``CMP0060`` provides compatibility for existing
|
||||||
|
projects.
|
||||||
|
|
||||||
|
The OLD behavior for this policy is to ask the linker to search for
|
||||||
|
libraries whose full paths are known to be in implicit link directories.
|
||||||
|
The NEW behavior for this policy is to link libraries by full path even
|
||||||
|
if they are in implicit link directories.
|
||||||
|
|
||||||
|
This policy was introduced in CMake version 3.3. Unlike most policies,
|
||||||
|
CMake version |release| does *not* warn by default when this policy
|
||||||
|
is not set and simply uses OLD behavior. See documentation of the
|
||||||
|
:variable:`CMAKE_POLICY_WARNING_CMP0060 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
|
||||||
|
variable to control the warning.
|
|
@ -0,0 +1,6 @@
|
||||||
|
link-implicit-libs-full-path
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Linking to library files by a full path in an implicit linker search
|
||||||
|
directory (e.g. ``/usr/lib/libfoo.a``) no longer asks the linker to
|
||||||
|
search for the library (e.g. ``-lfoo``). See policy :policy:`CMP0060`.
|
|
@ -11,6 +11,8 @@ warn by default:
|
||||||
policy :policy:`CMP0047`.
|
policy :policy:`CMP0047`.
|
||||||
* ``CMAKE_POLICY_WARNING_CMP0056`` controls the warning for
|
* ``CMAKE_POLICY_WARNING_CMP0056`` controls the warning for
|
||||||
policy :policy:`CMP0056`.
|
policy :policy:`CMP0056`.
|
||||||
|
* ``CMAKE_POLICY_WARNING_CMP0060`` controls the warning for
|
||||||
|
policy :policy:`CMP0060`.
|
||||||
|
|
||||||
This variable should not be set by a project in CMake code. Project
|
This variable should not be set by a project in CMake code. Project
|
||||||
developers running CMake may set this variable in their cache to
|
developers running CMake may set this variable in their cache to
|
||||||
|
|
|
@ -411,6 +411,10 @@ cmComputeLinkInformation
|
||||||
std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
|
std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
|
||||||
this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
|
this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->CMP0060Warn =
|
||||||
|
this->Makefile->PolicyOptionalWarningEnabled(
|
||||||
|
"CMAKE_POLICY_WARNING_CMP0060");
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -548,6 +552,22 @@ bool cmComputeLinkInformation::Compute()
|
||||||
// Add implicit language runtime libraries and directories.
|
// Add implicit language runtime libraries and directories.
|
||||||
this->AddImplicitLinkInfo();
|
this->AddImplicitLinkInfo();
|
||||||
|
|
||||||
|
if (!this->CMP0060WarnItems.empty())
|
||||||
|
{
|
||||||
|
std::ostringstream w;
|
||||||
|
w << (this->Makefile->GetCMakeInstance()->GetPolicies()
|
||||||
|
->GetPolicyWarning(cmPolicies::CMP0060)) << "\n"
|
||||||
|
"Some library files are in directories implicitly searched by "
|
||||||
|
"the linker when invoked for " << this->LinkLanguage << ":\n"
|
||||||
|
" " << cmJoin(this->CMP0060WarnItems, "\n ") << "\n"
|
||||||
|
"For compatibility with older versions of CMake, the generated "
|
||||||
|
"link line will ask the linker to search for these by library "
|
||||||
|
"name."
|
||||||
|
;
|
||||||
|
this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
|
||||||
|
this->Target->GetBacktrace());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,6 +1210,28 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the policy for whether we should use the approach below.
|
||||||
|
switch (this->Target->GetPolicyStatusCMP0060())
|
||||||
|
{
|
||||||
|
case cmPolicies::WARN:
|
||||||
|
if (this->CMP0060Warn)
|
||||||
|
{
|
||||||
|
// Print the warning at most once for this item.
|
||||||
|
std::string const& wid = "CMP0060-WARNING-GIVEN-" + item;
|
||||||
|
if (!this->CMakeInstance->GetPropertyAsBool(wid))
|
||||||
|
{
|
||||||
|
this->CMakeInstance->SetProperty(wid, "1");
|
||||||
|
this->CMP0060WarnItems.insert(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case cmPolicies::OLD:
|
||||||
|
break;
|
||||||
|
case cmPolicies::REQUIRED_ALWAYS:
|
||||||
|
case cmPolicies::REQUIRED_IF_USED:
|
||||||
|
case cmPolicies::NEW:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Many system linkers support multiple architectures by
|
// Many system linkers support multiple architectures by
|
||||||
// automatically selecting the implicit linker search path for the
|
// automatically selecting the implicit linker search path for the
|
||||||
// current architecture. If the library appears in an implicit link
|
// current architecture. If the library appears in an implicit link
|
||||||
|
|
|
@ -175,6 +175,10 @@ private:
|
||||||
std::vector<std::string> OldUserFlagItems;
|
std::vector<std::string> OldUserFlagItems;
|
||||||
bool OldLinkDirMode;
|
bool OldLinkDirMode;
|
||||||
|
|
||||||
|
// CMP0060 warnings.
|
||||||
|
bool CMP0060Warn;
|
||||||
|
std::set<std::string> CMP0060WarnItems;
|
||||||
|
|
||||||
// Runtime path computation.
|
// Runtime path computation.
|
||||||
cmOrderDirectories* OrderRuntimeSearchPath;
|
cmOrderDirectories* OrderRuntimeSearchPath;
|
||||||
void AddLibraryRuntimeInfo(std::string const& fullPath,
|
void AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||||
|
|
|
@ -390,6 +390,11 @@ cmPolicies::cmPolicies()
|
||||||
CMP0059, "CMP0059",
|
CMP0059, "CMP0059",
|
||||||
"Do no treat DEFINITIONS as a built-in directory property.",
|
"Do no treat DEFINITIONS as a built-in directory property.",
|
||||||
3,3,0, cmPolicies::WARN);
|
3,3,0, cmPolicies::WARN);
|
||||||
|
|
||||||
|
this->DefinePolicy(
|
||||||
|
CMP0060, "CMP0060",
|
||||||
|
"Link libraries by full path even in implicit directories.",
|
||||||
|
3,3,0, cmPolicies::WARN);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPolicies::~cmPolicies()
|
cmPolicies::~cmPolicies()
|
||||||
|
|
|
@ -118,6 +118,7 @@ public:
|
||||||
CMP0058, ///< Ninja requires custom command byproducts to be explicit
|
CMP0058, ///< Ninja requires custom command byproducts to be explicit
|
||||||
CMP0059, ///< Do not treat ``DEFINITIONS`` as a built-in directory
|
CMP0059, ///< Do not treat ``DEFINITIONS`` as a built-in directory
|
||||||
/// property.
|
/// property.
|
||||||
|
CMP0060, ///< Link libraries by full path even in implicit directories.
|
||||||
|
|
||||||
/** \brief Always the last entry.
|
/** \brief Always the last entry.
|
||||||
*
|
*
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
F(CMP0041) \
|
F(CMP0041) \
|
||||||
F(CMP0042) \
|
F(CMP0042) \
|
||||||
F(CMP0046) \
|
F(CMP0046) \
|
||||||
F(CMP0052)
|
F(CMP0052) \
|
||||||
|
F(CMP0060)
|
||||||
|
|
||||||
class cmake;
|
class cmake;
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Always build in a predictable configuration. For multi-config
|
||||||
|
# generators we depend on RunCMakeTest.cmake to do this for us.
|
||||||
|
if(NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Convince CMake that it can instruct the linker to search for the
|
||||||
|
# library of the proper linkage type, but do not really pass flags.
|
||||||
|
set(CMAKE_EXE_LINK_STATIC_C_FLAGS " ")
|
||||||
|
set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS " ")
|
||||||
|
|
||||||
|
# Make a link line asking for the linker to search for the library
|
||||||
|
# look like a missing object file so we will get predictable content
|
||||||
|
# in the error message. This also ensures that cases expected to use
|
||||||
|
# the full path can be verified by confirming that they link.
|
||||||
|
set(CMAKE_LINK_LIBRARY_FLAG LINKFLAG_)
|
||||||
|
set(CMAKE_LINK_LIBRARY_SUFFIX _LINKSUFFIX${CMAKE_C_OUTPUT_EXTENSION})
|
||||||
|
|
||||||
|
# Convince CMake that our library is in an implicit linker search directory.
|
||||||
|
list(APPEND CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||||
|
|
||||||
|
# Create a simple library file. Place it in our library directory.
|
||||||
|
add_library(CMP0060 STATIC cmp0060.c)
|
||||||
|
set_property(TARGET CMP0060 PROPERTY
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||||
|
|
||||||
|
# Add a target to link the library file by full path.
|
||||||
|
add_executable(main1 main.c)
|
||||||
|
target_link_libraries(main1 $<TARGET_FILE:CMP0060>)
|
||||||
|
add_dependencies(main1 CMP0060)
|
||||||
|
|
||||||
|
# Add a second target to verify the warning only appears once.
|
||||||
|
add_executable(main2 main.c)
|
||||||
|
target_link_libraries(main2 $<TARGET_FILE:CMP0060>)
|
||||||
|
add_dependencies(main2 CMP0060)
|
|
@ -0,0 +1,2 @@
|
||||||
|
cmake_policy(SET CMP0060 NEW)
|
||||||
|
include(CMP0060-Common.cmake)
|
|
@ -0,0 +1 @@
|
||||||
|
[^0]
|
|
@ -0,0 +1 @@
|
||||||
|
LINKFLAG_CMP0060_LINKSUFFIX
|
|
@ -0,0 +1,2 @@
|
||||||
|
cmake_policy(SET CMP0060 OLD)
|
||||||
|
include(CMP0060-Common.cmake)
|
|
@ -0,0 +1 @@
|
||||||
|
[^0]
|
|
@ -0,0 +1 @@
|
||||||
|
LINKFLAG_CMP0060_LINKSUFFIX
|
|
@ -0,0 +1 @@
|
||||||
|
include(CMP0060-Common.cmake)
|
|
@ -0,0 +1 @@
|
||||||
|
[^0]
|
|
@ -0,0 +1 @@
|
||||||
|
LINKFLAG_CMP0060_LINKSUFFIX
|
|
@ -0,0 +1,16 @@
|
||||||
|
^CMake Warning \(dev\) at CMP0060-Common.cmake:[0-9]+ \(add_executable\):
|
||||||
|
Policy CMP0060 is not set: Link libraries by full path even in implicit
|
||||||
|
directories. Run "cmake --help-policy CMP0060" for policy details. Use
|
||||||
|
the cmake_policy command to set the policy and suppress this warning.
|
||||||
|
|
||||||
|
Some library files are in directories implicitly searched by the linker
|
||||||
|
when invoked for C:
|
||||||
|
|
||||||
|
.*/Tests/RunCMake/CMP0060/CMP0060-WARN-ON-build/lib/(lib)?CMP0060.(a|lib)
|
||||||
|
|
||||||
|
For compatibility with older versions of CMake, the generated link line
|
||||||
|
will ask the linker to search for these by library name.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMP0060-WARN-ON.cmake:[0-9]+ \(include\)
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
This warning is for project developers. Use -Wno-dev to suppress it.$
|
|
@ -0,0 +1,2 @@
|
||||||
|
set(CMAKE_POLICY_WARNING_CMP0060 1)
|
||||||
|
include(CMP0060-Common.cmake)
|
|
@ -0,0 +1,3 @@
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
project(${RunCMake_TEST} C)
|
||||||
|
include(${RunCMake_TEST}.cmake)
|
|
@ -0,0 +1,19 @@
|
||||||
|
include(RunCMake)
|
||||||
|
|
||||||
|
function(run_cmake_CMP0060 CASE)
|
||||||
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0060-${CASE}-build)
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
||||||
|
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
||||||
|
|
||||||
|
run_cmake(CMP0060-${CASE})
|
||||||
|
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
||||||
|
run_cmake_command(CMP0060-${CASE}-Build
|
||||||
|
${CMAKE_COMMAND} --build . --config Debug
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
run_cmake_CMP0060(OLD)
|
||||||
|
run_cmake_CMP0060(WARN-OFF)
|
||||||
|
run_cmake_CMP0060(WARN-ON)
|
||||||
|
run_cmake_CMP0060(NEW)
|
|
@ -0,0 +1,4 @@
|
||||||
|
int libCMP0060(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
extern int libCMP0060(void);
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return libCMP0060();
|
||||||
|
}
|
|
@ -65,6 +65,7 @@ add_RunCMake_test(CMP0054)
|
||||||
add_RunCMake_test(CMP0055)
|
add_RunCMake_test(CMP0055)
|
||||||
add_RunCMake_test(CMP0057)
|
add_RunCMake_test(CMP0057)
|
||||||
add_RunCMake_test(CMP0059)
|
add_RunCMake_test(CMP0059)
|
||||||
|
add_RunCMake_test(CMP0060)
|
||||||
if(CMAKE_GENERATOR STREQUAL "Ninja")
|
if(CMAKE_GENERATOR STREQUAL "Ninja")
|
||||||
add_RunCMake_test(Ninja)
|
add_RunCMake_test(Ninja)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
\* CMP0042
|
\* CMP0042
|
||||||
\* CMP0046
|
\* CMP0046
|
||||||
\* CMP0052
|
\* CMP0052
|
||||||
|
\* CMP0060
|
||||||
|
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)
|
CMakeLists.txt:3 \(include\)
|
||||||
|
|
Loading…
Reference in New Issue