Merge topic 'target-link-libraries-interfaces'

b1f12f8 target_link_libraries: Simplify argument processing state tests
5fc95df target_link_libraries: Add missing space in documentation
9143822 target_link_libraries: Add LINK_(PUBLIC|PRIVATE) options
cf64218 target_link_libraries: Trim trailing whitespace
This commit is contained in:
David Cole 2011-11-23 08:16:10 -05:00 committed by CMake Topic Stage
commit 1ec3801a3a
11 changed files with 196 additions and 16 deletions

View File

@ -95,8 +95,8 @@ bool cmTargetLinkLibrariesCommand
bool haveLLT = false;
// Start with primary linking and switch to link interface
// specification when the keyword is encountered.
this->DoingInterface = false;
// specification if the keyword is encountered as the first argument.
this->CurrentProcessingState = ProcessingLinkLibraries;
// add libraries, nothe that there is an optional prefix
// of debug and optimized than can be used
@ -104,7 +104,7 @@ bool cmTargetLinkLibrariesCommand
{
if(args[i] == "LINK_INTERFACE_LIBRARIES")
{
this->DoingInterface = true;
this->CurrentProcessingState = ProcessingLinkInterface;
if(i != 1)
{
this->Makefile->IssueMessage(
@ -115,6 +115,32 @@ bool cmTargetLinkLibrariesCommand
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")
{
if(haveLLT)
@ -186,10 +212,12 @@ bool cmTargetLinkLibrariesCommand
cmSystemTools::SetFatalErrorOccured();
}
// If the INTERFACE option was given, make sure the
// LINK_INTERFACE_LIBRARIES property exists. This allows the
// command to be used to specify an empty link interface.
if(this->DoingInterface &&
// If any of the LINK_ options were given, make sure the
// LINK_INTERFACE_LIBRARIES target property exists.
// Use of any of the new keywords implies awareness of
// this property. And if no libraries are named, it should
// result in an empty link interface.
if(this->CurrentProcessingState != ProcessingLinkLibraries &&
!this->Target->GetProperty("LINK_INTERFACE_LIBRARIES"))
{
this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
@ -217,11 +245,15 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
cmTarget::LinkLibraryType llt)
{
// Handle normal case first.
if(!this->DoingInterface)
if(this->CurrentProcessingState != ProcessingLinkInterface)
{
this->Makefile
->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
return;
if (this->CurrentProcessingState != ProcessingPublicInterface)
{
// Not LINK_INTERFACE_LIBRARIES or LINK_PUBLIC, do not add to interface.
return;
}
}
// Get the list of configurations considered to be DEBUG.

View File

@ -19,7 +19,7 @@
*
* cmTargetLinkLibrariesCommand is used to specify a list of libraries to link
* into executable(s) or shared objects. The names of the libraries
* should be those defined by the LIBRARY(library) command(s).
* should be those defined by the LIBRARY(library) command(s).
*/
class cmTargetLinkLibrariesCommand : public cmCommand
{
@ -27,7 +27,7 @@ public:
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
virtual cmCommand* Clone()
{
return new cmTargetLinkLibrariesCommand;
}
@ -47,12 +47,12 @@ public:
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
virtual const char* GetTerseDocumentation()
{
return
return
"Link a target to given libraries.";
}
/**
* More documentation.
*/
@ -107,6 +107,18 @@ public:
"Libraries specified as \"general\" (or without any keyword) are "
"treated as if specified for both \"debug\" and \"optimized\"."
"\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 "
"case of mutually-dependent STATIC libraries CMake allows the graph "
"to contain cycles (strongly connected components). "
@ -130,14 +142,21 @@ public:
")"
;
}
cmTypeMacro(cmTargetLinkLibrariesCommand, cmCommand);
private:
void LinkLibraryTypeSpecifierWarning(int left, int right);
static const char* LinkLibraryTypeNames[3];
cmTarget* Target;
bool DoingInterface;
enum ProcessingState {
ProcessingLinkLibraries,
ProcessingLinkInterface,
ProcessingPublicInterface,
ProcessingPrivateInterface
};
ProcessingState CurrentProcessingState;
void HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt);
};

View File

@ -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 "")

View File

@ -0,0 +1,7 @@
#include "depA.h"
int DepA::foo()
{
return 0;
}

View File

@ -0,0 +1,7 @@
#include "depa_export.h"
struct DEPA_EXPORT DepA
{
int foo();
};

View File

@ -0,0 +1,11 @@
#include "depB.h"
#include "depA.h"
int DepB::foo()
{
DepA a;
return 0;
}

View File

@ -0,0 +1,7 @@
#include "depb_export.h"
struct DEPB_EXPORT DepB
{
int foo();
};

View File

@ -0,0 +1,13 @@
#include "depC.h"
int DepC::foo()
{
return 0;
}
DepA DepC::getA()
{
DepA a;
return a;
}

View File

@ -0,0 +1,12 @@
#include "depc_export.h"
#include "depA.h"
struct DEPC_EXPORT DepC
{
int foo();
DepA getA();
};

View File

@ -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();
}

View File

@ -1658,6 +1658,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
-P "${CMake_SOURCE_DIR}/Tests/CMakeCommands/build_command/RunCMake.cmake"
)
ADD_TEST_MACRO(CMakeCommands.target_link_libraries target_link_libraries)
CONFIGURE_FILE(
"${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
"${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"