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

Reply via email to