Compiling the same source code, with the same compiler and version, activating or deactivating C++ std features might lead to different native code (type sizes, etc).
Is this related to setting '-std=c++11' or '-std=gnu14' compiler flag? I've been setting this as an option in a lot of my builds to address this. I've just taken on the task of converting an entire Makefile-based build system to use conan + Artifactory as well as upgrade from c++03 to c++17. Having this as part of the compiler setting would be extremely helpful for me.
If this is related to what I suggested, we should have the ability to distinguish between an extended capability vs a standard capability. For example, adding CMAKE_CXX_STANDARD=14 as a CMake build definition for GCC (haven't confirmed clang) will default to adding -std=gnu++14 flag. However, if you also add CMAKE_CXX_EXTENSIONS=OFF, then it will yield -std=c++14 (effectively turning off GNU extensions). NOTE: I'd prefer to have this generated as a property of the install (conanbuildinfo.cmake) rather than have this passed in as build parameters. We can discuss pros and cons of each approach.
Using the CMake flags as an example of how to handle this issue, I suggest supporting (using settings.yml):
compiler:
gcc:
standard:
version: [98, 11, 14, 17]
allow_extensions: false
An alternative approach would be specifying the exact flag values
compiler:
gcc:
standard: ["c++98", "c++11", "c++14", "c++1z", "gnu++98", "gnu++11", "gnu++14", "gnu++1z"]
The benefits of the second approach is that customizing this value can be easily achieved since it's essentially a string substitution.
The first approach has the benefit that the version is independent of the flag passed in. For example, to get c++17 functionality on GCC 7.1, you have to pass in -std=c++1z. When the user decides to upgrade to GCC 8+, then they'd need to update the flag in the second approach, but not the first. This would make the first approach more resilient to compiler flag changes (I'm guessing this is why CMake decided to use this approach).
I've been tracking a similar discussion on the clang developers mailing list recently and want to point out that clang is considering changing their current behavior, so whatever's done here, be sure to keep that in mind.
The current consensus appears to be "if you don't specify a C++ standard, we will use the latest stable one" which is different from the current behavior of "if you don't specify a C++ standard, we will pick [x]". I am also a fan of the former (proposed) approach.
What I'm not sure of is whether or not conan should be aware of the fact that a C++ standard needed to be selected (whether or not it was actively chosen). I have two conflicting arguments:
Further complicating the second item there is that I imagine a lot of C++11-specific libraries actually work for C++11 and later, but won't work for C++98, so if I want to release two separate packages, then the C++98 one is easy but I'm not aware of a conan feature that would let me say "this works with C++11, 14, and 17". That means I'm creating (at least) 4 packages for which I really only have two versions.
Regarding 2. @grafikrobot has confirmed that the code generated with a different standard might not be cross-standard compatible. Like even some type sizes might change.
Regarding 1, while I like the approach that clang is taking to choose the default compiler, I don't think that will apply neatly to conan. The problem is that a compiler will change which standard they use as a result of implementing the newest standard and its acceptance, but conan needs to be backwards compatible. For example, my new job is still using GCC 4.8. The default standard for that compiler is gnu++98. If you use the new clang standard model within conan, the default will be c++14, which isn't even available in GCC 4.8.
We could...
I'm a fan of either 2 or 3. Option 3 should be a bit faster to execute (hash tables vs invoking an external process). Option 2 will be more forward-compatible (we can always just query a compiler, but tables will need to be updated as compilers are being released)
My concern here is that, in all cases (1 or 2 or 3), all the existing packages in servers won't be located anymore, because if we fill (forcing the user or automatically detecting it) the standard setting, the ID of the package will change.
About the @mpdelbuono comment:
Some libraries might work with multiple versions, and I don't want to release a different package for C++98 and C++11 consumers if they're cross-standard compatible.
It could be controlled in two ways:
package_id() method, so you can use the same package for several different standards.None value in the compiler.standard (or whatever name), so unless a user specifies it, it will be ignored and the current packages will be located (SHA won't change). In this case we won't solve the issue of the standards automatically. Maybe if someone wants to force the specification of the standard, the user could remove the "None" from the settings.yml possible values.Life would be so much easier without backwards-compatibility :)
Actually, I like the idea of allowing None in the compiler.standard. I still feel that we should be able to break up compiler.standard into parts signifying the version (e.g. 11, 14, 17, 20, ...) and whether to allow compiler extensions (e.g. gnu++11 vs c++11). However, setting compiler.standard to None will allow backwards compatibility by not changing the SHA.
I'd like to make note that I'm not a fan of allowing 0x, 1x, 1y, 1z, etc versions. I acknowledge that C++11 took much longer than expected. However, the ISO committee is now operating on a very good and consistent release schedule that having the two digit year is better than putting a weird letter in there. In other words, 1z is 17. Conan should be smart enough to do the proper translation.
Hi all! @skizzay @grafikrobot @solvingj
I'm implementing a default setting for cppstd and cstd versions. I have an implementation as a subsetting of each compiler but we found some issues:
So maybe we should add another option for that, instead of a subsetting, (we could think in a better way to manage "standard" options, like shared and the std), but then you could mix different standards.
We checked in the slack Conan channel that it's not safe at all to mix them, so options could be problematic, but we have wildcard options -o *:cppstd=17.
So, in any case, we can make the build helpers (CMake, Autotools, etc) and generators work automatically irrespective if it's an option or a setting.
@skizzay What's your experience so far using options? Would it be ok using options?
Note that we will try to implement something like (still don't know if possible):
def configure_options(self):
self.options.add_cppstd_option()
self.options.add_shared_option()
That way we could avoid repeating the almost "standard" options and even change the possible values depending on the settings, for example, for Visual Studio the option would have these values:
cppstd: [11, 14, 17]
And for the rest:
cppstd: [98, 11, 14, 17, 98gnu, 11gnu, 14gnu, 17gnu]
@lasote I haven't run into the pure C libraries since each of the libraries that I've ported were C++. That said, I can see where this would be a problem. This brings me back full circle to my original suggestion that we should specify the value that gets used as the standard. For example, GCC has c90, c89 for ISO C90 applications and gnu90 and gnu89 for ISO C90 plus some extensions. As far as C++ is concerned, there's been precedent that the "upcoming" standard will have a letter. For a while C++11 was C++0x and then C++1x, with C++14 -> C++1y, and C++17 -> C++1z. I have no idea what they're calling C++20 just yet, but I think it's safe to bet that there'll be a standard implementation in the compiler that indicates the user wants the latest standard that hasn't been yet voted upon (experimental to some degree). By allowing the user specify c90 or gnu++14 or whatever is supported by the compiler, then we'll save ourselves some headaches when it comes to future-proofing new standards.
@skizzay C++ >= 20 will use C++2a, C++2b, and C++2c.
We are using cpp_info.cppflags for libraries that require some c++ standard in the interface.
It is essential that we can mix different standards in one project.
Example:
(We are using Visual Studio. )
<optional> -> min. c++17std::random_shuffle in some header file -> max. c++14You cannot consume A and B at the same time, but an intermediate C could consume A and provide an interface that is compatible with B:
A - C
\
B - D
cpp_info.cppflags is compiler specific. An abstraction as with CMake's target_compile_features would be nice. Also, if you consume A and B with incompatible compiler flags, you could end up with the compiler just ignoring one of them.
Btw: There is already a setting compiler.libcxx. How is that related? Why is it only used for some specific compilers in the cmake generator? I would expect something like
if(CONAN_LIBCXX STREQUAL "libstdc++11")
set(CMAKE_CXX_STANDARD 11)
# or target_compile_features(target PUBLIC cxx_std_11)
endif()
@wpalfi libcxx is only related with the standard library and for gcc>=5 the ABI. Docs explaining it are not released yet:
@wpalfi Further, checking CONAN_LIBCXX won't tell us which specific standard to use or if we want to enable/disable extensions. To expand on your example
if(CONAN_LIBCXX STREQUAL "libstdc++11")
set(CMAKE_CXX_STANDARD 11) # What about C++14, C++17, C++20, C++23, ...?
set(CMAKE_CXX_EXTENSIONS ON) # How do I determine if these should be disabled?
endif()
In the listing below, we keep the standard version and extensions separated from the compiler itself. This enables two things: specify the compiler independently of the standard (e.g. 'gnu++14' works fine with GCC but isn't friendly towards MSVC) and allows the generator to create the appropriate output.
compiler:
standard:
version: [98, 03, 11, 14, 17, 20]
extensions: true/false
In the above example, the cmake generator would set the appropriate variables
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS OFF)
Further, the gcc generator would add the following flag to conanbuildinfo.gcc
-std=c++14
The downside of this approach is that each generator must be updated to handle this change as well as add support for each new standard that comes out (though this should be happening only every 3 years or so).
@lasote Do we have anyone working on this yet or is it strictly just discussing what we want the behavior to be?
We have 2 opened PR by myself, one using settings and one using options:
https://github.com/conan-io/conan/pull/2030
https://github.com/conan-io/conan/pull/2042
Both are little outdated because we are not convinced that neither of both approaches is the ideal solution. It is assigned to the 1.1 but I don't know if we are going to take a decision yet.
@lasote I looked at those PRs. Of the two, I like #2030 the best. I think it should be a setting rather than an option. That said, I'm not entirely sure that I would distinguish between C and C++ when specifying the standard. In order to get a "correct" C build, the user would have to remove cppstd and vice versa. I still feel that having version and extensions as a compiler.standard subsetting with None being valid for both for backward compatibility in SHA generation is the way to go.
Tomorrow we will try to gather all the pro and cons of both approaches and will update.