How to use the modulemap Clang feature under Windows? - c++

When I try to use import statements within C++20 with the modules feature under a Windows environment, I am not able to make it work because I must doing something wrong.
The key thing is that I tried different options on the cmd args without success (take any possible variation), like:
-fimplicit-modules -fbuiltin-module-map -fimplicit-module-maps
what relegates me to the use of the #include directives in the module purview, and it's provoking this kind of bug (related question Clang error including headers in C++ projects)
How does Clang should be instructed in order to find the modulemap that enables the usage of import statements for system headers under Windows (MSVC toolchain assumed).
Thanks.

Related

VSCode C++ Intellisense can't discern C++20 features

I try to run codes like
#include <string>
#include <iostream>
int main() {
std::string str = "This is a string";
std::cout << str.starts_with("name");
}
But intellisense will give out an error
"std::__cxx11::basic_string<char, std::char_traits,
std::allocator>" has no member "starts_with" C/C++(135) [6,9]
And It still can be build and produce a correct result.
Also it can find implementation in header file.
But the macro __cplusplus is defined as 201703L
I've already added a command -std=c++20 when building, why this happened?
Compiler: minGW 11.2 compiled by msys2
Assuming you are using Microsoft's C/C++ extension, you must configure the extension to use C++ 20 standard for intellisense.
The easiest way to do this is to add the line "C_Cpp.default.cppStandard": "c++20" to your settings.json file. You can also find the setting in the GUI under the name "Cpp Standard". Selecting c++20 from its dropdown will achieve the same result.
Note that this setting is, by default, set as a global user defaults. You can configure it per-workspace by selecting the Workspace tab in the settings GUI and changing that Cpp Standard dropdown to c++20.
As for why adding the -std=c++20 flag didn't work: -std=c++20 just tells your compiler which standard to use to build your code. 'Intellisense' does not receive this flag because it is a separate tool from the compiler and is therefore not required to support all the standards the compiler supports. It may support less even, although Intellisense tools usually support as current a standard as possible. Therefore the language standard for Intellisense must be configured separately from the compiler (in this case).
Final Note: After changing the setting, try closing and re-opening VS Code. In my experience changing the language standard setting can cause some weirdness to happen. Closing and re-opening VS Code seems to ensure the setting changes take full effect.

Import std lib as modules with clang

I am experimenting with modules in clang, and would like to include the standard lib as modules instead of as includes.
Currently I do this
#include <iostream>
#include <string>
It seems that you in msvc should be able to import standard libs with for example
import std.core;
When using clang however this does not seem to be implemented, or implemented in another way.
My question is: Is it possible to import stl-includes like microsoft suggest, or is it possible to map standard lib includes to modules somhow.
Note: The reason I cannot use #include <...> or #import <...> is because of other errors that might get its own question. So I think that getting import std.core or similar is the way to go now if it is possible.
ModernesCpp also mentions std.core.
The C++20 standard does not include module definitions for the C++ standard library. Visual Studio does (unfortunately), and a lot of bad sites out there will act like this is standard. But it's not; it's just a Microsoft thing.
If you want to include the C++ standard library through a module across platforms, you will have to either use import <header-name> syntax or write your own standard library modules that import the headers and export specific C++ declarations.
I solved your task. Below are instructions for doing this. I did this on my Win 10 64-bit using CLang from current release of LLVM 12.0 (taken from here), also I have MSVC 2019 v16.9.4 Community installed (taken from here).
Note. This answer is for CLang only, I also wrote similar answer for MSVC.
First create following files:
module.modulemap:
module std_mod {
requires cplusplus17
header "std_mod.hpp"
export *
}
std_mod.hpp:
#include <iostream>
#include <map>
#include <set>
#include <vector>
use.cpp:
import std_mod;
int main() {
std::cout << "Hello, World!" << std::endl;
}
In above file std_mod.hpp you can put any std headers that you need. You should put all possible STD headers that you use in all your projects, to be able to share same precomiled STD module everywhere.
Then execute command:
clang++ -### use.cpp -c -std=c++20 -m64 -g -O3 >use.txt 2>&1
Here instead of -std=c++20 -m64 -g -O3 you may use any options needed for your project. Every precompiled module should have same compilation options as other .cpp files to be able to be linked into final binary.
Command above will produce use.txt with options that you need to copy. In this options you should remove -emit-obj option, -o option (and path after it), also remove use.cpp. Then add to this command options string module.modulemap -o std_mod.pcm -emit-module -fmodules -fmodule-name=std_mod. On my system I got following resulting command:
"D:\\bin\\llvm\\bin\\clang++.exe" "-cc1" module.modulemap -o std_mod.pcm -emit-module -fmodules -fmodule-name=std_mod "-triple" "x86_64-pc-windows-msvc19.28.29914" "-mincremental-linker-compatible" "--mrelax-relocations" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "use.cpp" "-mrelocation-model" "pic" "-pic-level" "2" "-mframe-pointer=none" "-fmath-errno" "-fno-rounding-math" "-mconstructor-aliases" "-munwind-tables" "-target-cpu" "x86-64" "-tune-cpu" "generic" "-gno-column-info" "-gcodeview" "-debug-info-kind=limited" "-resource-dir" "D:\\bin\\llvm\\lib\\clang\\12.0.0" "-internal-isystem" "D:\\bin\\llvm\\lib\\clang\\12.0.0\\include" "-internal-isystem" "d:\\bin2\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\include" "-internal-isystem" "d:\\bin2\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\atlmfc\\include" "-internal-isystem" "D:\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\shared" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\um" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\winrt" "-O3" "-std=c++20" "-fdeprecated-macro" "-fdebug-compilation-dir" "D:\\t\\t4" "-ferror-limit" "19" "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility" "-fms-compatibility-version=19.28.29914" "-fdelayed-template-parsing" "-fno-implicit-modules" "-fcxx-exceptions" "-fexceptions" "-vectorize-loops" "-vectorize-slp" "-faddrsig" "-x" "c++"
As you can see this command contains full paths to includes, they are necessary. Execute command above, it will produce std_mod.pcm that you can use in your projects everywhere with same compilation options.
Why long command above is needed? Because using .modulemap file is possible only through -cc1 command, which executes low-level CLang front end instead of simplified CLang driver (driver is without -cc1 option). This low level front-end is possible to do many tricks which driver can't do.
Now you can compile your final program use.cpp that does import std_mod; by next command:
clang++ use.cpp -o use.exe -std=c++20 -m64 -g -O3 -fmodule-file=std_mod.pcm
See that I added -fmodule-file=std_mod.pcm - such option is needed for every imported module. As alternative you can use -fprebuilt-module-path=<directory> to specify where to search for all prebuilt modules.
Not long time ago I also created question and answer here regarding how to make modules out of headers in CLang.
For further instructions regarding modules see CLang's Modules Doc and CommandLine Doc.
PS. Why I implemented quite long solution above? Because at least on Windows' CLang next simple program
import <iostream>;
int main() {}
doesn't compile, it says use.cpp:1:8: error: header file <iostream> (aka 'd:\bin2\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29910\include\iostream') cannot be imported because it is not known to be a header unit. So at least on Win one needs a special solution, solution with import <header-name>; doesn't work here.
All headers imported through import <header>; or import "header"; syntax should have special compiled header unit modules placed into special folder to be able to use. And on Win STD headers don't have corresponding compiled header unit modules. Also after spending many hours I didn't find a way in CLang how to create these so-called header units on Win. Only solution above solved my task of importing headers as modules.
I found where I got the Idea, llvms documentation. There is a section stating
"As an example, the module map file for the C standard library might look a bit like this:"
module std [system] [extern_c] {
module assert {
textual header "assert.h"
header "bits/assert-decls.h"
export *
}
module complex {
header "complex.h"
export *
}
module ctype {
header "ctype.h"
export *
}
module errno {
header "errno.h"
header "sys/errno.h"
export *
}
module fenv {
header "fenv.h"
export *
}
// ...more headers follow...
}
It seems that you then name this file something.modulemap and send it to the compiler. A quick googling did not find any similar solution for msvc (other than std.io discussed earlier).
I have not tried it out yet, i guess i will accept my own answer when I have, or if somebody else comes up with something better.

How to specify c++ 14/17 with bazel.rc (tool specific to using GCC /G++, project not open to other tool chains)

Within my bazel.rc file for the C++ Bazel build options, I have specified:
'build --cxxopt="-std=c++1y"'
When I try to change to build --cxxopt="-std=c++14", bazel Throws error of :
''build --cxxopt="-std=c++14"' is not an option'
, with a cursor below 4 in c++14. If I change the 4 to y (c++1y), it compiles with no problem. I tried adding 'std:make_unique' in my code (c++14 addition) , and it clearly does not compile (make _unique is not part of std) which is assume is complaining that c++14 is not set as the standard, hence no make_unique for me.
What is the latest supported version of C++ in bazel? More specifically, how do I enable C++14 / C++17 (and even C++2x) for Bazel build, it those are supported? Thanks!
NOTE: this is not the same as How to set C++ standard version when build with Bazel??. (I am not asking about cpp 11 and I am asking about a very specific toolchain -- GCC/g++) I am not using any of the tools suggested by that thread. I am using GCC / g++ and am restricted in not being able to use the tools suggested by the answer in the previous question, I've RTFMd and googled. Thanks in advance.

Does clang provide an unlink implementation?

I am trying to compile a library using clang. The library makes calls to 'unlink', which is not defined by clang:
libmv/src/third_party/OpenExif/src/ExifImageFileWrite.cpp:162:17: error: use of undeclared identifier 'unlink'; did you mean 'inline'?
unlink( mTmpImageFile.c_str() ) ;
My question is, what is the clang equivalent of unlink? As I see it, the path forward would be to #define unlink somewhere with an equivalent routine.
There is no "Clang equivalent". Neither GCC nor Clang have ever been responsible for defining unlink, though they do probably distribute the POSIX headers which do (I don't recall specifically where POSIX headers come from).
Unfortunately, this appears to be a bug with the library you're using; the OpenExif developers failed to include the correct headers. Different C++ implementations may internally #include various headers for their own purposes, which has apparently masked this bug on your previous toolchain.
You can hack your copy and/or submit a patch to add:
#include <unistd.h>

How can I use a C++11 to program the Arduino?

How can I use C++11 when programming the Arduino?
I would be fine using either the Arduino IDE or another environment. I am most interested in the core language improvements, not things that require standard library changes.
As of version 1.6.6, the Arduino IDE enables C++11 by default.
For older versions, read on:
It is very easy to change the flags for any element of the toolchain, including the assembler, compiler, linker or archiver.
Tested on the Arduino IDE version 1.5.7 (released on July 2014),
Locate the platform.txt file,
AVR architecture => {install path}\hardware\arduino\avr\platform.txt
SAM architecture => {install path}\hardware\arduino\sam\platform.txt
Inside that file, you can change any flag, for instance,
compiler.c.flags for changing the default compilation flags for C++ files.
compiler.cpp.flags for changing the default compilation flags for C++ files.
You can also change any of the "recipes" or compile patters, at the corresponding section of the configuration file, under the title "AVR/SAM compile patterns".
After making the changes, you must restart the Arduino IDE, at least on version 1.5.7.
For instance,
To enable support for C++11 (C++0x), tested on Arduino IDE versions 1.5.7 and 1.5.8, you will simply add the flag "-std=gnu++11" at the end of the line starting with compiler.cpp.flags=".
It is expected that C++11 is enabled by default in the near future on the Arduino IDE. However, as of version 1.5.8 (Oct 2014) it is still not the case.
Arduino IDE 1.6.6 and newer have C++11 enabled by default (they have the compiler flag "-std=gnu++11" set in the platform.txt file).
Firstly, only GCC 4.7 and above (and therefore AVR-GCC 4.7 and above) support C++11. So, check the versions installed with:
gcc --version
avr-gcc --version
If AVR-GCC is 4.7 or higher, then you may be able to use C++11.
The Arduino IDE does not support custom compiler flags. This has been requested, but has not yet been implemented.
So, you are left with having to use other environments or to compile your program directly from the command line.
In case, of compiling directly from the command line using AVR-GCC, you simply need to add an extra compiler flag for enabling C++11 support.
-std=c++11
For specific development environments, most would support editing of the compiler flags from the build options within the IDE. The above mentioned flag needs to be added to the list of flags for each environment.
C++0x was the name of working draft of the C++11 standard. C++0x support is available GCC 4.3 onwards. However, this is strictly experimental support so you cannot reliably expect C++11 features to be present. Here is the complete list of features available with the corresponding version of GCC. The availability of features in AVR-GCC will be the same as what's available in the corresponding GCC version.
The compiler flag for C++0x is:
-std=c++0x
Please, note, that there is no easy way to specify additional flags from Arduino IDE or use other IDE (Eclipse, Code::Blocks, etc.) or command line.
As a hack, you can use a small proxy program (should be cross-platform):
//============================================================================
// Name : gcc-proxy.cpp
// Copyright : Use as you want
// Description : Based on http://stackoverflow.com/questions/5846934/how-to-pass-a-vector-to-execvp
//============================================================================
#include <unistd.h>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main(int argc, char *argv[]) {
vector<string> arguments;
vector<const char*> aptrs;
// Additional options, one per line
ifstream cfg((string(argv[0]) + ".ini").c_str());
if (cfg.bad())
cerr << "Could not open ini file (you're using proxy for some reason, er?)" << endl;
string arg;
while (cfg) {
getline(cfg, arg);
if(arg == "\r" || arg == "\n")
continue;
arguments.push_back(arg);
}
for (const string& arg : arguments)
aptrs.push_back(arg.c_str());
for (int i = 1; i < argc; ++i)
aptrs.push_back(argv[i]);
// Add null pointer at the end, execvp expects NULL as last element
aptrs.push_back(nullptr);
// Pass the vector's internal array to execvp
const char **command = &aptrs[0];
return execvp(command[0], command);
}
Compile the program.
Rename the original avr-g++.exe to avr-g++.orig.exe (or any other name).
Create avr-g++.ini file where the first line is FULL path to the original program (e.g. D:\Arduino\hardware\tools\avr\bin\avr-g++.orig.exe) and add additional parameters, one per line, as desired.
You're done!
Example avr-g++.ini:
D:\Arduino\hardware\tools\avr\bin\avr-g++.orig.exe
-std=c++0x
I use Ino and this worked:
ino build -cppflags="-std=c++0x"
This generated a hex file at least 15k in size (that's with optimizations turned on), compared to about 5k for the standard build, which is a consideration for a poor little ATmega328. It might be okay for one of the microcontrollers with a lot more program space.
If you need more control and a better IDE, I recommend using Sloeber Plugin for Eclipse or the Sloeber IDE itself.
Creating more complicated code is much easier using this IDE. It also allows to add flags to the compiler (C, C++ and linker). So to customize the compile, just right click on project and select Properties. In the Properties window, select Arduino → Compiler Option. This way you can add options to your build.