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