I am trying to change the C++ Standard from version 17 to 20 so I can use the jthread lib.
On my root CMakelists.txt of the project I added :
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
But when I build the project again and check which version the program is running, it is still the C++ 17 version and not C++ 20.
I check the version running the following lines :
if (__cplusplus == 201703L)
std::cout << "C++17\n";
else if (__cplusplus == 201402L)
std::cout << "C++14\n";
else if (__cplusplus == 201103L)
std::cout << "C++11\n";
else if (__cplusplus == 199711L)
std::cout << "C++98\n";
else if (__cplusplus == 202002L)
std::cout << "C++20\n";
else
std::cout << "pre-standard C++\n";
I am using the g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, which from what I read it supports c++ 20,g++_C++20
Does anyone has any idea of why this is happening ?
__cplusplus reports the version of the standard but its definition isn't entirely clear. GCC seems to only define it to 202002 from GCC 11 when presumably the implementation reached some arbitrary level of completion.
It is instead better to test for the existence of the specific feature you want to use using the feature test macros for example to check for std::jthread support:
#include <thread>
#ifndef __cpp_lib_jthread
#error this code requires std::jthread
#endif
Note that std::jthread is only available with libstdc++ 10: https://godbolt.org/z/eqP4j4eq1
Related
I am writing a code for macOS application.
The application would be running on M1 based Macs as well as Intel based Macs also.
What would be the switch to differentiate M1 and Intel?
if (M1)
{
do something for M1
}
else if (Intel)
{
do something for Intel
}
I think, you can use __arm__ to detect arm architecture:
#ifdef __arm__
//do smth on arm (M1)
#else
//do smth on x86 (Intel)
#endif
I was just fooling around with this and found this reference for Objective-C from apple that seemed to work with clang for C++.
// Objective-C example
#include "TargetConditionals.h"
#if TARGET_OS_OSX
// Put CPU-independent macOS code here.
#if TARGET_CPU_ARM64
// Put 64-bit Apple silicon macOS code here.
#elif TARGET_CPU_X86_64
// Put 64-bit Intel macOS code here.
#endif
#elif TARGET_OS_MACCATALYST
// Put Mac Catalyst-specific code here.
#elif TARGET_OS_IOS
// Put iOS-specific code here.
#endif
https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary
I specifically checked to see if TARGET_CPU_ARM64 was defined in my header.
Hopefully this helps someone.
If you need a runtime check instead of compile time check, you can think of using something like below
#include <sys/sysctl.h>
#include <mach/machine.h>
int main(int argc, const char * argv[])
{
cpu_type_t type;
size_t size = sizeof(type);
sysctlbyname("hw.cputype", &type, &size, NULL, 0);
int procTranslated;
size = sizeof(procTranslated);
// Checks whether process is translated by Rosetta
sysctlbyname("sysctl.proc_translated", &procTranslated, &size, NULL, 0);
// Removes CPU_ARCH_ABI64 or CPU_ARCH_ABI64_32 encoded with the Type
cpu_type_t typeWithABIInfoRemoved = type & ~CPU_ARCH_MASK;
if (typeWithABIInfoRemoved == CPU_TYPE_X86)
{
if (procTranslated == 1)
{
cout << "ARM Processor (Running x86 application in Rosetta)";
}
else
{
cout << "Intel Processor";
}
}
else if (typeWithABIInfoRemoved == CPU_TYPE_ARM)
{
cout << "ARM Processor";
}
}
I need to be able to list the files in a directory, and so I'm trying to upgrade my C++ version in CodeBlocks to C++ 17 so i can use filesystem. To do this I followed the steps outlined at http://candcplusplus.com/enable-c17-in-code-blocks-mingw-gcc-for-all-version-with-pictures#:~:text=Enabling%20the%20C%2B%2B17,Create%20a%20project.
I didnt have to change much, CodeBlocks 20.03 and MinGW 8.1.0 are already installed. MinGW is already in my path from when I built wxWidgets. The Settings->Compiler...->Toolchain executables tab I didnt have to make any changes to, and appears in CodeBlocks as:
I also checked the box to use C++ 17 in compiler settings like so
I ran the test program on the website with the instructions and got "True!".
However when I change the basic test program to this, to try and use filesystem to read files in a directory, I get an error:
#include <iostream>
#include <filesystem>
using namespace std;
int main()
{
const int i=90;
if constexpr (i) //'if constexpr' is part of C++17
{
cout << "True!";
}
else
{
cout<<"False" ;
}
std::string path = "../MagicProgCPP/files/debug images/";
for (const auto & entry : filesystem::directory_iterator(path))
{
cout << entry.path() << std::endl;
}
cin.get();
return 0;
}
The program stops building, opens the file fs_path.h and stops on this line:
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (__p.is_absolute()
|| (__p.has_root_name() && __p.root_name() != root_name())) <----- ******STOPS HERE
operator=(__p);
else
{
string_type __pathname;
if (__p.has_root_directory())
__pathname = root_name().native();
else if (has_filename() || (!has_root_directory() && is_absolute()))
__pathname = _M_pathname + preferred_separator;
__pathname += __p.relative_path().native(); // XXX is this right?
_M_pathname.swap(__pathname);
_M_split_cmpts();
}
#else
// Much simpler, as any path with root-name or root-dir is absolute.
if (__p.is_absolute())
operator=(__p);
else
{
if (has_filename() || (_M_type == _Type::_Root_name))
_M_pathname += preferred_separator;
_M_pathname += __p.native();
_M_split_cmpts();
}
#endif
return *this;
}
I get this error in the build log:
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\fs_path.h|237|error: no match for 'operator!=' (operand types are 'std::filesystem::__cxx11::path' and 'std::filesystem::__cxx11::path')|
I'm prety confident the path exists as I entered it and there's files in it. The build log message suggests maybe I'm not using C++17? But when I click build, this is the line the program uses to build:
g++.exe -Wall -fexceptions -g -Wall -std=c++17 -c E:\testc17\main.cpp -o obj\Debug\main.o
What am I doing wrong? Thanks
The bug 78870 was fixed since 2018-07.
You should add to project options -> linker settings -> link libraries the following library: stdc++fs.
I tried to compile your code with MinGW gcc 8.1.0 (via CodeBlocks) and everything works well (clearly with another path, since I don't have the same directories as you).
You could also add a check on the existence of the search directory like this:
namespace fs = std::filesystem;
std::string mypath { "../MyDir" };
if(fs::exists(mypath))
{
for(const auto & entry : fs::directory_iterator(path))
{
cout << entry.path() << std::endl;
}
}
It appears that this exact problem is a known bug in mingw 8.1. The bug report is here: https://sourceforge.net/p/mingw-w64/bugs/737/
and has the error in the same location:
operator != is declared and defined in line 550, but referenced in line 237.
The problem is triggered by operator/= in line 233:
path& operator/=(const path& __p)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (__p.is_absolute()
|| (__p.has_root_name() && __p.root_name() != root_name()))
operator=(__p);
else
{
string_type __pathname;
if (__p.has_root_directory())
__pathname = root_name().native();
else if (has_filename() || (!has_root_directory() && is_absolute()))
__pathname = _M_pathname + preferred_separator;
__pathname += __p.relative_path().native(); // XXX is this right?
_M_pathname.swap(__pathname);
_M_split_cmpts();
}
The bug report said this was fixed in master meaning you need to install a version of mingw with the fix applied. I believe the best method is to upgrade mingw to a version greater than 8.1
user4581301 commented above in the main question that the following link has instructions on how to get a mingw install: How to install MinGW-w64 and MSYS2?
I wrote below code to detect OS and it is working fine with boost version > 1.55 but older boost library ( e.g. 1.48 ) do not support operating system macros.
Below is the sample code that works fine with boost >= 1.55.
std::string GetOSPlatform()
{
std::string platformStr = "Unknown";
#if defined(BOOST_OS_MACOS) || defined(BOOST_OS_IOS)
platformStr = "osx";
#endif
#if defined(BOOST_OS_WINDOWS)
platformStr = "windows";
#if BOOST_ARCH_X86_64
platformStr += "-x64";
#endif
#endif
#if defined(BOOST_OS_UNIX) || defined(BOOST_OS_LINUX)
platformStr = "linux";
#if BOOST_ARCH_X86_64
platformStr += "-x64";
#endif
#endif
#if BOOST_OS_SOLARIS
platformStr = "solaris";
#if BOOST_ARCH_SPARC
platformStr += "-sparc";
#else
platformStr += "-x64";
#endif
#endif
#if BOOST_OS_HPUX
platformStr = "hp-ux";
#endif
return platformStr;
}
int main()
{
std::string pltform = GetOSPlatform();
std::cout << "platform....." << pltform << std::endl;
return 0;
}
Here "BOOST_OS_*" macros are not supported with boost version < 1.55 so how to replace above code so that it works with older boost version as well ?
Any suggestions?
In order to get the code to work, you add some conditional compilation based on the version of Boost that you are running. If it's 1.55 or later, you just compile the code as it is. If it's an earlier version, you simply reproduce the OS detection code that later Boost versions use locally, e.g. by simply copying the code from a later version.
I'm learning about pthread_cond_t and wrote the following code intended to block forever at the pthread_cond_wait():
// main.cpp
// Intentionally blocks forever.
#include <iostream>
#include <cstring>
#include <cerrno>
#include <pthread.h>
int main( int argc, char* argv[] )
{
pthread_cond_t cond;
if ( pthread_cond_init( &cond, NULL ) )
{
std::cout << "pthread_cond_init() failed: " << errno << "(" << strerror( errno ) << ")" << std::endl;
}
pthread_mutex_t mutex;
if ( pthread_mutex_init( &mutex, NULL ) )
{
std::cout << "pthread_mutex_init() failed: " << errno << "(" << strerror( errno ) << ")" << std::endl;
}
pthread_mutex_lock( &mutex );
pthread_cond_wait( &cond, &mutex );
pthread_cond_destroy( &cond );
return 0;
}
When I first compiled/executed this program, the executable did not hang - it exited:
>g++ --version
g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>g++ -g main.cpp && ./a.out
> // <-- Note: returned to bash prompt
Next I tried linking against libpthread - and now the executable hung, as expected:
>g++ -g main.cpp -lpthread && ./a.out
^C
> // <-- Needed to send SIGINT to terminate process
I was actually expecting to hit a link error for the required pthread functions; why did I not encounter one when I did not explicitly link against libpthread?
This question may be rendered moot by the answer to the above, but when compiling without the explicit link the libpthread, why did the resulting binary "skip over" or ignore the pthead_cond_wait()? Is there some default do-nothing implementation for pthread functions in glibc or somewhere?
Some glibc functions need locking when your process is multithreaded.
To avoid dragging in the libpthread dependency everytime because of that, glibc uses weakrefs to refer to a bunch of pthread functionality. If it detects the functionality is not available (which won't cause a linker error because of the weakref solution) it will default those ops to no-ops (which is just fine because if you don't have pthreads, you can't be multithreaded and locking isn't needed).
The upshot of this solution is the behavior you're getting.
i try to build a cmake which use two different version of boost. ( I use a framework which only runs with boost 1.55 but my application needs boost 1.57)
My idea was to make 2 Cmake build processes
Application Cmake boost 1.57
cmake_minimum_required (VERSION 2.6)
project (Application)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=auto -std=c++0x ")
set(Boost_DEBUG ON)
set(Boost_NO_SYSTEM_PATHS TRUE)
set(BOOST_ROOT /opt/boost/boost_1_57)
find_package(Boost 1.57 REQUIRED COMPONENTS thread filesystem log system)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
SYSTEM /opt/boost/boost_1_57/include
)
ADD_LIBRARY( AppLib SHARED testVersion.cpp ...)
Framework Cmake boost 1.55
cmake_minimum_required(VERSION 2.8.3)
project(Test)
add_subdirectory(Application)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=auto -std=c++0x ")
set(Boost_NO_SYSTEM_PATHS TRUE)
set(BOOST_ROOT $ENV{BOOST_ROOT})
find_package(Boost 1.55 REQUIRED COMPONENTS thread filesystem log system)
include_directories(
SYSTEM ${Boost_INCLUDE_DIRS}
)
add_executable(test test.cpp)
target_link_libraries( test AppLib )
test.cpp
#include "testVersion.hpp"
int main() {
std::cout << "Main call Using Boost "
<< BOOST_VERSION / 100000 << "." // major version
<< BOOST_VERSION / 100 % 1000 << "." // minior version
<< BOOST_VERSION % 100 // patch level
<< std::endl;
std::cout << "library : " << std::endl;
Version v;
v.callVersion();
}
testVersion
#include "testVersion.hpp"
void Version::callVersion()
{ std::cout << "Using Boost "
<< BOOST_VERSION / 100000 << "." // major version
<< BOOST_VERSION / 100 % 1000 << "." // minior version
<< BOOST_VERSION % 100 // patch level
<< std::endl;
}
testVersion.hpp
#include <boost/version.hpp>
class Version
{
public:
void callVersion();
};
If i do it this way it runs well :
Output:
Main call Using Boost 1.55.0
Using Boost 1.57.0
But when I eliminate the testVersion.cpp file and inline my callVersion I get the output:
Main call Using Boost 1.55.0
library :
Using Boost 1.55.0
because the compiler use for the headers boost 1.55 only when i include boost in the source files he takes 1.57. How i can solve that ? is that possible?
Conclusion:
I need an empty header :
all_boost_includes.hpp
with a all_boost_includes.cpp
#include "boost..."
#include ...
which will just include all boost headers. And then i have to include this header in every header in my application. Is that correct?
This is similar to an precompiled boost header or?
I tried include "boost_headers.hpp" which is empty and has a boost_header.cpp which includes boost versions
I added on my Application cmake
ADD_LIBRARY( AppLib SHARED boost_headers.cpp)
But when i try
#include "precompiled_boost.hpp"
#include <fstream>
#include <iostream>
class Version
{
public:
void callVersion(){
std::cout << "Using Boost "
<< BOOST_VERSION / 100000 << "." // major version
<< BOOST_VERSION / 100 % 1000 << "." // minior version
<< BOOST_VERSION % 100 // patch level
<< std::endl;
}
};
He don't know BOOST_VERSION. What I have to do there ? If i include precompiled_boost.cpp i get the wrong output
1. If you do not inline callVersion
Compiling library compiles code for Version::callVersion within the library. As library uses boost 1.55 Version::callVersion will return 1.55.
2. If you do inline callVersion
Compiling library does not compile code for Version::callVersion within the library, because it will bi inlined! Your Version::callVersion will actually be compiled on the test side. As test uses boost 1.57, Version::callVersion will return 1.57
Conclusion
You should not inline you calls. More, you cannot use classes that refer to any boost in their declarations in both application and library projects that use different versions of boost. If you have to, you should consider creating some proxy objects or functions, so all boost stuff will be encapsulated inside your library.