Stephen Kelly wrote:
> Stephen Kelly wrote:
>> I still think you should revisit my review mail on point 2 too.
>
> Something that becomes possible when thinking about the above and target
> properties is interface requirements.
I've implemented a prototype which has better API than your module.
In my concept:
* Applying the -std=c++11 flag is the responsibility of CMake, not the user.
* CMake determines the -std= flag to use (GCC 4.9 has -std=c++1y by now). It
won't add '-std=c++11 -std=c++14', but just '-std=c++14'
* Required compiler features are scoped to targets.
* Target properties are set, exported and transitively evaluated track the
compiler features required.
* Compiler requirements can be optional, in which case -D defines are
generated in the (PUBLIC) COMPILE_DEFINITIONS
* The -D defines are for scoping or replacement, depending on what the
feature calls for.
* Required compiler features are listed in the INTERFACE of exported
targets. CMake evaluates whether the compiler is capable of using the
IMPORTED targets it is supposed to use transitively, in a similar way to the
POSITION_INDEPENDENT_CODE feature.
* A new command target_compiler_feature is introduced with two signatures:
target_compiler_feature(<target> <PUBLIC|PRIVATE>
REQUIRED <feature1> [<feature2> ...])
target_compiler_feature(<target> <PUBLIC|PRIVATE>
OPTIONAL <feature> DEFINE <define_name>)
* Another non-target-scoped command could be introduced, similar to
target_compile_options -> add_compile_options.
This is better in many noteworthy ways to the cxx11 topic in the stage.
Brad, do you have any response to any part of anything I wrote about that
topic?
Thanks,
Steve.
#include "foo.h"
A::A(int i, void *p)
: num(i), ptr(p)
{
}
A::A(const A &other)
: num(other.num), ptr(other.ptr)
{
}
A::~A()
{
}
A& A::operator=(const A &other)
{
num = other.num;
ptr = other.ptr;
return *this;
}
B::B(int i, void *p)
: A(i, ptr)
{
}
#include <utility>
template<typename T>
struct Factory
{
// Variadic templates and macros required to use this library by design. Not guarded by any macro.
template<typename... Args>
static T Create(Args&&... args) { return T(std::forward<Args>(args)...); }
};
#define CREATE(TYPE, ...) Factory< TYPE >::Create(__VA_ARGS__)
class A
{
template<typename> friend class Factory;
friend class B;
int num;
void *ptr;
A(int i, void *p = Foo_NULLPTR);
public:
#if Foo_RVALUE_REFS
inline A(A&& other) : num(other.num), ptr(other.ptr)
{
other.num = 0;
other.ptr = 0;
}
inline A &operator=(A&& other)
{
std::swap(num, other.num);
std::swap(ptr, other.ptr);
return *this;
}
#endif
inline A(const A &other);
inline A &operator=(const A &other);
virtual ~A();
virtual void doSomething() {}
virtual void doSomethingElse() {}
};
class B : public A
{
template<typename> friend class Factory;
B(int i, void *ptr = Foo_NULLPTR);
public:
void doSomething() Foo_OVERRIDE {}
void doSomethingElse() Foo_FINAL {}
};
#include "foo.h"
int main(int argc, char **argv)
{
auto a = CREATE(A, 47, new long);
auto b = CREATE(B, 42);
}
# FIXME: Encode this stuff into Modules/Compiler/*.cmake
if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
set(CMAKE_C_COMPILER_FEATURES)
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
list(APPEND CMAKE_C_COMPILER_FEATURES
variadic_macros
)
endif()
set(CMAKE_C99_STANDARD_COMPILE_OPTION -std=c99)
# FIXME: This feature listing is not complete.
set(CMAKE_CXX98_COMPILER_FEATURES)
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.3)
list(APPEND CMAKE_CXX98_COMPILER_FEATURES
member_templates
template_template_parameters
template_friends
)
endif()
set(CMAKE_CXX11_COMPILER_FEATURES)
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.3)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
decltype
rvalue_refs
static_assert
variadic_macros
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
auto_type
default_members
deleted_members
variadic_templates
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
nullptr
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
final
override
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
list(APPEND CMAKE_CXX14_COMPILER_FEATURES
# binary_literals
generalized_lambda_capture
return_type_deduction
)
endif()
set(CMAKE_CXX_COMPILER_FEATURES
binary_literals
${CMAKE_CXX98_COMPILER_FEATURES}
${CMAKE_CXX11_COMPILER_FEATURES}
${CMAKE_CXX14_COMPILER_FEATURES}
)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.3)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9
# AND VERSION_LESS 4.11 # Speculative
)
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y")
endif()
# if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.11) # Speculative
# set(CMAKE_CXX14_STANDARD_COMPILE_OPTION -std=c++14)
# endif()
# set(CMAKE_CXX17_STANDARD_COMPILE_OPTION -std=c++17) # Speculative
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL MSVC)
# FIXME: This feature listing is not complete.
set(CMAKE_CXX_COMPILER_FEATURES)
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1400)
list(APPEND CMAKE_CXX_COMPILER_FEATURES
variadic_macros
final
override
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1600)
list(APPEND CMAKE_CXX_COMPILER_FEATURES
auto_type
lambda
decltype
rvalue_refs
static_assert
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1400
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 1700)
set(CMAKE_CXX_COMPILER_FEATURE_COMPAT_final sealed)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "XL")
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.1)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
auto
decltype
delegating_constructors
static_assert
variadic_templates
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
constexpr
rvalue_references
)
endif()
set(CMAKE_CXX_COMPILER_FEATURES
${CMAKE_CXX11_COMPILER_FEATURES}
)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.1)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-qlanglvl=extended0x")
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.1)
if(WIN32)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "/Qstd=c++0x")
else()
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
endif()
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
func_identifier
long_long
static_assert
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
auto
decltype
defaulted_functions
deleted_functions
lambda
rvalue_references
static_assert
)
endif()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
variadic_templates
)
endif()
# constexpr is partially supported in version 13, it may
# already show up for this version depending on the check file.
# The same applies to initializer lists.
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13)
if(WIN32)
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "/Qstd=c++11")
else ()
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
endif ()
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
nullptr
)
endif ()
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14)
list(APPEND CMAKE_CXX11_COMPILER_FEATURES
override
final
constexpr
delegating_constructors
initializer_list
)
endif()
set(CMAKE_CXX_COMPILER_FEATURES
${CMAKE_CXX11_COMPILER_FEATURES}
)
endif()
set(CMAKE_CXX_COMPILER_FEATURE_COMPAT_nullptr 0)
# End of stuff that goes into Modules/Compiler/*.cmake
# FIXME: Implement this in C++ as a command
function(target_compiler_feature TARGET_NAME SCOPE REQUEST_FORM FEATURE_NAME)
# FIXME: Use a target property so that we can hack this without changing
# cmake C++ implementation, for this prototype only.
list(FIND CMAKE_CXX11_COMPILER_FEATURES ${FEATURE_NAME} needs11)
list(FIND CMAKE_CXX14_COMPILER_FEATURES ${FEATURE_NAME} needs14)
list(FIND CMAKE_CXX17_COMPILER_FEATURES ${FEATURE_NAME} needs17)
if(NOT needs17 EQUAL -1)
set(standard 17)
elseif(NOT needs14 EQUAL -1)
set(standard 14)
elseif(NOT needs11 EQUAL -1)
set(standard 11)
endif()
get_target_property(current ${TARGET_NAME} CXX_STANDARD)
if (NOT current OR standard GREATER current)
set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD ${standard})
endif()
if (REQUEST_FORM STREQUAL OPTIONAL)
if(NOT ${ARGC} EQUAL 6)
message(FATAL_ERROR "Bad parameters!")
endif()
if(NOT ${ARGV4} STREQUAL DEFINE)
message(FATAL_ERROR "Bad parameters!")
endif()
set(define_name ${ARGV5})
set(FEATURES_DEFINE_REPLACE
final
override
nullptr
default_members
deleted_members
)
set(FEATURES_DEFINE_SCOPE
variadic_templates
variadic_macros
lambda
rvalue_refs
static_assert # ### Can be replacement, but requires struct definition in user code. CMake can't help there.
)
list(FIND FEATURES_DEFINE_REPLACE ${FEATURE_NAME} define_replace)
if(NOT define_replace EQUAL -1)
set(define_replacement $<$<BOOL:$<TARGET_PROPERTY:CXX_COMPILER_FEATURE_${FEATURE_NAME}>>:${FEATURE_NAME}>)
set(define_replacement ${define_replacement}$<$<NOT:$<BOOL:$<TARGET_PROPERTY:CXX_COMPILER_FEATURE_${FEATURE_NAME}>>>:${CMAKE_CXX_COMPILER_FEATURE_COMPAT_${FEATURE_NAME}}>)
target_compile_definitions(${TARGET_NAME} ${SCOPE} ${define_name}=${define_replacement})
else()
list(FIND FEATURES_DEFINE_SCOPE ${FEATURE_NAME} define_scope)
if(define_scope EQUAL -1)
message(FATAL_ERROR "Bad parameters!")
endif()
target_compile_definitions(${TARGET_NAME} ${SCOPE} ${define_name}=$<BOOL:$<TARGET_PROPERTY:CXX_COMPILER_FEATURE_${FEATURE_NAME}>>)
endif()
return()
endif()
if (NOT REQUEST_FORM STREQUAL REQUIRED)
message(FATAL_ERROR "Bad parameters!")
endif()
set(features ${FEATURE_NAME} ${ARGN})
foreach(feature ${features})
set_property(TARGET ${TARGET_NAME} PROPERTY INTERFACE_CXX_COMPILER_FEATURE_${feature} 1)
set_property(TARGET ${TARGET_NAME} APPEND PROPERTY COMPATIBLE_INTERFACE_STRING CXX_COMPILER_FEATURE_${feature})
endforeach()
endfunction()
cmake_minimum_required(VERSION 2.8)
project(User)
# FIXME: Should be built-in and implemented in C++.
include(CompilerFeatures.cmake)
add_library(somelib SHARED foo.cpp)
target_compiler_feature(somelib PUBLIC OPTIONAL final DEFINE Foo_FINAL)
target_compiler_feature(somelib PUBLIC OPTIONAL override DEFINE Foo_OVERRIDE)
target_compiler_feature(somelib PUBLIC OPTIONAL nullptr DEFINE Foo_NULLPTR)
target_compiler_feature(somelib PUBLIC OPTIONAL rvalue_refs DEFINE Foo_RVALUE_REFS)
# This means that variadic_templates are unconditionally needed to compile somelib headers.
target_compiler_feature(somelib PUBLIC REQUIRED variadic_templates variadic_macros)
add_executable(user main.cpp)
target_link_libraries(user somelib)
target_compiler_feature(user PRIVATE REQUIRED auto_type)
# FIXME: This needs to be implemented in C++ in CMake. Hacking here for illustration.
# After configuring, CMake should iterate over all entries which could be in ${CXX_COMPILER_FEATURES}, and
# for any item not in the list, it should
# set CXX_COMPILER_FEATURE_${FEATURE_NAME} to 0. That way, if a target is built with, for example, GCC 4.3 but uses
# an imported target with INTERFACE_CXX_COMPILER_FEATURE_variadic_templates set to 1,
# an error is generated at generate-time.
# It also needs to add the -std=c++11 flag if required.
foreach(FEATURE_NAME ${CMAKE_CXX_COMPILER_FEATURES})
set_property(TARGET user somelib PROPERTY CXX_COMPILER_FEATURE_${FEATURE_NAME} 1)
endforeach()
# FIXME: Needs to be transitive property in C++ implementation evaluated at generate-time.
get_target_property(standard user CXX_STANDARD)
if(standard AND CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION)
target_compile_options(user PRIVATE ${CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION})
endif()
get_target_property(standard somelib CXX_STANDARD)
if(standard AND CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION)
target_compile_options(somelib PRIVATE ${CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION})
endif()
export(TARGETS somelib NAMESPACE Foo:: FILE FooTargets.cmake)
# #######
# Separate consuming project
include(${CMAKE_CURRENT_BINARY_DIR}/FooTargets.cmake)
add_executable(consumer main.cpp)
# If this project uses a compiler which does not support variadic_macros or variadic_templates,
# cmake can report that as an error diagnostic because Foo::somelib has
# INTERFACE_CXX_COMPILER_FEATURE_variadic_macros "1"
# INTERFACE_CXX_COMPILER_FEATURE_variadic_templates "1"
# COMPATIBLE_INTERFACE_STRING "CXX_COMPILER_FEATURE_variadic_templates;CXX_COMPILER_FEATURE_variadic_macros"
target_link_libraries(consumer Foo::somelib)
target_compiler_feature(consumer PRIVATE REQUIRED auto_type)
foreach(FEATURE_NAME ${CMAKE_CXX_COMPILER_FEATURES})
set_property(TARGET consumer PROPERTY CXX_COMPILER_FEATURE_${FEATURE_NAME} 1)
endforeach()
# FIXME: Needs to be transitive property in C++ implementation evaluated at generate-time.
get_target_property(standard consumer CXX_STANDARD)
if(standard AND CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION)
target_compile_options(consumer PRIVATE ${CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION})
endif()
# #######
--
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
Please keep messages on-topic and check the CMake FAQ at:
http://www.cmake.org/Wiki/CMake_FAQ
Follow this link to subscribe/unsubscribe:
http://public.kitware.com/cgi-bin/mailman/listinfo/cmake-developers