target_link_libraries: Add LINK_(PUBLIC|PRIVATE) options
Makes it possible to specify the link dependencies and link interfaces in one command without repetition.
This commit is contained in:
parent
cf64218eeb
commit
914382224d
|
@ -95,8 +95,8 @@ bool cmTargetLinkLibrariesCommand
|
||||||
bool haveLLT = false;
|
bool haveLLT = false;
|
||||||
|
|
||||||
// Start with primary linking and switch to link interface
|
// Start with primary linking and switch to link interface
|
||||||
// specification when the keyword is encountered.
|
// specification if the keyword is encountered as the first argument.
|
||||||
this->DoingInterface = false;
|
this->CurrentProcessingState = ProcessingLinkLibraries;
|
||||||
|
|
||||||
// add libraries, nothe that there is an optional prefix
|
// add libraries, nothe that there is an optional prefix
|
||||||
// of debug and optimized than can be used
|
// of debug and optimized than can be used
|
||||||
|
@ -104,7 +104,7 @@ bool cmTargetLinkLibrariesCommand
|
||||||
{
|
{
|
||||||
if(args[i] == "LINK_INTERFACE_LIBRARIES")
|
if(args[i] == "LINK_INTERFACE_LIBRARIES")
|
||||||
{
|
{
|
||||||
this->DoingInterface = true;
|
this->CurrentProcessingState = ProcessingLinkInterface;
|
||||||
if(i != 1)
|
if(i != 1)
|
||||||
{
|
{
|
||||||
this->Makefile->IssueMessage(
|
this->Makefile->IssueMessage(
|
||||||
|
@ -115,6 +115,32 @@ bool cmTargetLinkLibrariesCommand
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(args[i] == "LINK_PUBLIC")
|
||||||
|
{
|
||||||
|
if(i != 1 && this->CurrentProcessingState != ProcessingPrivateInterface)
|
||||||
|
{
|
||||||
|
this->Makefile->IssueMessage(
|
||||||
|
cmake::FATAL_ERROR,
|
||||||
|
"The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
|
||||||
|
"argument, just after the target name."
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this->CurrentProcessingState = ProcessingPublicInterface;
|
||||||
|
}
|
||||||
|
else if(args[i] == "LINK_PRIVATE")
|
||||||
|
{
|
||||||
|
if(i != 1 && this->CurrentProcessingState != ProcessingPublicInterface)
|
||||||
|
{
|
||||||
|
this->Makefile->IssueMessage(
|
||||||
|
cmake::FATAL_ERROR,
|
||||||
|
"The LINK_PUBLIC or LINK_PRIVATE option must appear as the second "
|
||||||
|
"argument, just after the target name."
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this->CurrentProcessingState = ProcessingPrivateInterface;
|
||||||
|
}
|
||||||
else if(args[i] == "debug")
|
else if(args[i] == "debug")
|
||||||
{
|
{
|
||||||
if(haveLLT)
|
if(haveLLT)
|
||||||
|
@ -186,11 +212,13 @@ bool cmTargetLinkLibrariesCommand
|
||||||
cmSystemTools::SetFatalErrorOccured();
|
cmSystemTools::SetFatalErrorOccured();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the INTERFACE option was given, make sure the
|
// If any of the LINK_ options were given, make sure the
|
||||||
// LINK_INTERFACE_LIBRARIES property exists. This allows the
|
// LINK_INTERFACE_LIBRARIES target property exists.
|
||||||
// command to be used to specify an empty link interface.
|
// Use of any of the new keywords implies awareness of
|
||||||
if(this->DoingInterface &&
|
// this property. And if no libraries are named, it should
|
||||||
!this->Target->GetProperty("LINK_INTERFACE_LIBRARIES"))
|
// result in an empty link interface.
|
||||||
|
if((this->CurrentProcessingState != ProcessingLinkLibraries)
|
||||||
|
&& !this->Target->GetProperty("LINK_INTERFACE_LIBRARIES"))
|
||||||
{
|
{
|
||||||
this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
|
this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
|
||||||
}
|
}
|
||||||
|
@ -217,11 +245,15 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
|
||||||
cmTarget::LinkLibraryType llt)
|
cmTarget::LinkLibraryType llt)
|
||||||
{
|
{
|
||||||
// Handle normal case first.
|
// Handle normal case first.
|
||||||
if(!this->DoingInterface)
|
if(this->CurrentProcessingState != ProcessingLinkInterface)
|
||||||
{
|
{
|
||||||
this->Makefile
|
this->Makefile
|
||||||
->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
|
->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
|
||||||
return;
|
if (this->CurrentProcessingState != ProcessingPublicInterface
|
||||||
|
|| this->CurrentProcessingState == ProcessingPrivateInterface)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the list of configurations considered to be DEBUG.
|
// Get the list of configurations considered to be DEBUG.
|
||||||
|
|
|
@ -107,6 +107,18 @@ public:
|
||||||
"Libraries specified as \"general\" (or without any keyword) are "
|
"Libraries specified as \"general\" (or without any keyword) are "
|
||||||
"treated as if specified for both \"debug\" and \"optimized\"."
|
"treated as if specified for both \"debug\" and \"optimized\"."
|
||||||
"\n"
|
"\n"
|
||||||
|
" target_link_libraries(<target>\n"
|
||||||
|
" <LINK_PRIVATE|LINK_PUBLIC>\n"
|
||||||
|
" [[debug|optimized|general] <lib>] ...\n"
|
||||||
|
" [<LINK_PRIVATE|LINK_PUBLIC>\n"
|
||||||
|
" [[debug|optimized|general] <lib>] ...])\n"
|
||||||
|
"The LINK_PUBLIC and LINK_PRIVATE modes can be used to specify both the"
|
||||||
|
"link dependencies and the link interface in one command. "
|
||||||
|
"Libraries and targets following LINK_PUBLIC are linked to, and are "
|
||||||
|
"made part of the LINK_INTERFACE_LIBRARIES. Libraries and targets "
|
||||||
|
"following LINK_PRIVATE are linked to, but are not made part of the "
|
||||||
|
"LINK_INTERFACE_LIBRARIES. "
|
||||||
|
"\n"
|
||||||
"The library dependency graph is normally acyclic (a DAG), but in the "
|
"The library dependency graph is normally acyclic (a DAG), but in the "
|
||||||
"case of mutually-dependent STATIC libraries CMake allows the graph "
|
"case of mutually-dependent STATIC libraries CMake allows the graph "
|
||||||
"to contain cycles (strongly connected components). "
|
"to contain cycles (strongly connected components). "
|
||||||
|
@ -137,7 +149,14 @@ private:
|
||||||
static const char* LinkLibraryTypeNames[3];
|
static const char* LinkLibraryTypeNames[3];
|
||||||
|
|
||||||
cmTarget* Target;
|
cmTarget* Target;
|
||||||
bool DoingInterface;
|
enum ProcessingState {
|
||||||
|
ProcessingLinkLibraries,
|
||||||
|
ProcessingLinkInterface,
|
||||||
|
ProcessingPublicInterface,
|
||||||
|
ProcessingPrivateInterface
|
||||||
|
};
|
||||||
|
|
||||||
|
ProcessingState CurrentProcessingState;
|
||||||
|
|
||||||
void HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt);
|
void HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
project(target_link_libraries)
|
||||||
|
|
||||||
|
file(WRITE
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/main.cxx"
|
||||||
|
"int main() { return 0; }
|
||||||
|
"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
target_link_libraries
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/main.cxx"
|
||||||
|
)
|
||||||
|
|
||||||
|
macro(ASSERT_PROPERTY _target _property _value)
|
||||||
|
get_target_property(_out ${_target} ${_property})
|
||||||
|
if (NOT _out)
|
||||||
|
set(_out "")
|
||||||
|
endif()
|
||||||
|
if (NOT "${_out}" STREQUAL "${_value}")
|
||||||
|
message(SEND_ERROR "Target ${_target} does not have property ${_property} with value ${_value}. Actual value: ${_out}")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
include(GenerateExportHeader)
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
add_library(depA SHARED depA.cpp)
|
||||||
|
generate_export_header(depA)
|
||||||
|
|
||||||
|
add_library(depB SHARED depB.cpp)
|
||||||
|
generate_export_header(depB)
|
||||||
|
|
||||||
|
target_link_libraries(depB LINK_PRIVATE depA)
|
||||||
|
|
||||||
|
add_library(depC SHARED depC.cpp)
|
||||||
|
generate_export_header(depC)
|
||||||
|
|
||||||
|
target_link_libraries(depC LINK_PUBLIC depA)
|
||||||
|
|
||||||
|
assert_property(depA LINK_INTERFACE_LIBRARIES "")
|
||||||
|
assert_property(depB LINK_INTERFACE_LIBRARIES "")
|
||||||
|
assert_property(depC LINK_INTERFACE_LIBRARIES "depA")
|
||||||
|
|
||||||
|
add_executable(targetA targetA.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(targetA LINK_INTERFACE_LIBRARIES depA depB)
|
||||||
|
|
||||||
|
assert_property(targetA LINK_INTERFACE_LIBRARIES "depA;depB")
|
||||||
|
|
||||||
|
set_target_properties(targetA PROPERTIES LINK_INTERFACE_LIBRARIES "")
|
||||||
|
|
||||||
|
assert_property(targetA LINK_INTERFACE_LIBRARIES "")
|
||||||
|
|
||||||
|
target_link_libraries(targetA depB depC)
|
||||||
|
|
||||||
|
assert_property(targetA LINK_INTERFACE_LIBRARIES "")
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#include "depA.h"
|
||||||
|
|
||||||
|
int DepA::foo()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#include "depa_export.h"
|
||||||
|
|
||||||
|
struct DEPA_EXPORT DepA
|
||||||
|
{
|
||||||
|
int foo();
|
||||||
|
};
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
#include "depB.h"
|
||||||
|
|
||||||
|
#include "depA.h"
|
||||||
|
|
||||||
|
int DepB::foo()
|
||||||
|
{
|
||||||
|
DepA a;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#include "depb_export.h"
|
||||||
|
|
||||||
|
struct DEPB_EXPORT DepB
|
||||||
|
{
|
||||||
|
int foo();
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#include "depC.h"
|
||||||
|
|
||||||
|
int DepC::foo()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DepA DepC::getA()
|
||||||
|
{
|
||||||
|
DepA a;
|
||||||
|
return a;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#include "depc_export.h"
|
||||||
|
|
||||||
|
#include "depA.h"
|
||||||
|
|
||||||
|
struct DEPC_EXPORT DepC
|
||||||
|
{
|
||||||
|
int foo();
|
||||||
|
|
||||||
|
DepA getA();
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#include "depB.h"
|
||||||
|
#include "depC.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
DepA a;
|
||||||
|
DepB b;
|
||||||
|
DepC c;
|
||||||
|
|
||||||
|
return a.foo() + b.foo() + c.foo();
|
||||||
|
}
|
|
@ -1574,6 +1574,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
|
||||||
-P "${CMake_SOURCE_DIR}/Tests/CMakeCommands/build_command/RunCMake.cmake"
|
-P "${CMake_SOURCE_DIR}/Tests/CMakeCommands/build_command/RunCMake.cmake"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ADD_TEST_MACRO(CMakeCommands.target_link_libraries target_link_libraries)
|
||||||
|
|
||||||
CONFIGURE_FILE(
|
CONFIGURE_FILE(
|
||||||
"${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
|
"${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
|
||||||
"${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"
|
"${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"
|
||||||
|
|
Loading…
Reference in New Issue