Clang and C++ Module TS - c++

I have difficulty getting modules ts work on clang (both supplied with Xcode 9.3 beta and latest 7.0.0 trunk). I checked out other answers both here and on other platforms but I still can't figure it out. Here is what I have so far:
main.cpp
#include <iostream>
import stuff;
int main() {
std::cout << whatever() << "\n";
}
module.cppm
export module stuff;
export int whatever() {
return 5;
}
Following various recommendations, I have done this:
clang -fmodules-ts -std=c++17 --precompile -o stuff.pcm module.cppm
clang -fmodules-ts -std=c++17 -fmodule-file=stuff.pcm main.cpp
This results in linker error (whatever() not found). I am not sure how to proceed here.
Notes: I tried -fprebuilt-module-path=. instead of -fmodule-file and then it complains about unknown modules.
If someone can tell me how to set it up within Xcode, even better.
Disclaimer: I am not interested in a solution using module maps and traditional include. My interest in modules is not about improving compile times but about properly modularising my code (especially template code). Right now all my code is in header files anyway with the majority of functions declared as static.

It turns out that one needs to compile the precompiled module file as well, either by compiling it to an object file and then linking that file, or via a shortcut:
clang++ -fmodules-ts -std=c++17 -o main -fmodule-file=module.pcm main.cpp module.pcm
I guess this makes some sense (if one sees modules as AST dumps, and hence just another kind of source file). I have also found out that one can use -fprebuilt-module-path=. option instead of specifying -fmodule-file if the name of the module and the name of the module file is the same.
That said, there are a lot of things that still confuse me. For instance, attributes such as always_inline or noinline don't seem to be honoured. The compiler will inline functions though when optimisation is on.

Related

Is it possible to use a C++ named module without an object file?

I'm trying to compile a simple empty module example (using gcc 11.2):
// my_module.cc:
export my_module;
// main.cc:
import my_module;
int main() { return 0; }
Using these compilation commands:
g++ my_module.cc -std=c++20 -fmodules-ts -c
g++ main.cc -std=c++20 -fmodules-ts my_module.o
This compiles fine.
However, even though the module is empty, I need the module's object file (my_module.o) when compiling main.cc, because the linker wants the function _ZGIW9my_moduleEv. I'm assuming this function is meant to perform initialization for static variables or something similar, as it will call __static_initialization_and_destruction_0 if I define static variables in the module.
My question is, does every module really need an object file? Is there any way to mark a named module as "doesn't need initialization, all my functions are inline"?
I think that header units could be used like this, but they're supposedly meant only as a transitory solution and have other downsides like macro hygiene.

Having difficulties compiling simple c++ program on the command line with multiple files; maybe a linker error?

Sorry for the simple question. I am attempting to learn more c++ at a fundamental level. I have always used VS in the past, and I am trying to learn the command line and compile, navigate, etc. with it.
I started with "hello world" and was able to compile it with gcc/clang, then run it with the expected results.
I then slightly reworked this and made a new header/cpp file to do the output part of hello world, and then call that from the main function, described below:
main.cpp:
#include "MyClass.h"
int main(){
foo();
return 0;
}
MyClass.h
#pragma once
void foo();
MyClass.cpp
#include "MyClass.h"
#include <iostream>
void foo(){
std::cout << "Hello World\n";
}
I then have tried to compile with gcc and clang as follows:
clang -Wall -g main.cpp MyClass.cpp
I have tried the same with GCC, and have also tried various invocations of this, such as using -c:
clang -Wall -g -c main.cpp
clang -Wall -g -c MyClass.cpp
Each and every time, I get an error
λ clang -Wall -g MyClass.cpp main.cpp
main.cpp:13:1: error: use of undeclared identifier 'foo'
foo();
^
1 error generated.
I get this same error whether using gcc or clang.
I also tried from scratch on my laptop, to see if there was some more global issue, but I still get the same problem.
I have also tried on the basic Windows command line as well.
Other areas on StackOverflow demonstrate simple ways of compiling multiple files from the command line, and I have tried as they show, but still get errors.
I also know that "make" is something I need to learn as well, however, I just want to make sure I understand what my make file is doing before I dive into that.
I feel like it must be something trivial that I just cannot figure out.
Thank you to Andreas for the suggestion of looking at the preprocessor output. And thank you to everyone for the suggestions.
The pre-processor output did not make sense to what I was compiling.
I was using VSCode, in this case, as a text editor, making brand new files in my folder after launching it from the command line. I thought the files I created in VSCode directly into the folder (named main.cpp, for example), would produce a regular text file. However, for some reason, it did not.
Essentially, I recreated the above program in notepad and was easily able to compile it using the commands I used above. I guess VSCode may not be perfect for me as a pure text editor or I should figure out if there are settings to change to accomplish my goal.
Thank you all again for your time and consideration.
Use extern on your function. Also make sure you're compiling with c++ and not c; i.e. g++.
MyClass.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
extern void foo();
#ifdef __cplusplus
}
#endif

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.

Error compiling CPP application. "error: 'posix_memalign' was not declared in this scope"

I'm trying to compile a CPP application (an open source project) in the latest cygwin64 environment using g++ 6.4.0 and I get the following error:
error: 'posix_memalign' was not declared in this scope
now posix_memlign can be found in stdlib.h if you compile the most simple CPP "hello world" application there wouldn't be a problem calling posix_memlign.
The make file of the project report the following setup for the compilation
g++ -DHAVE_CONFIG_H -I. -Wall -Wnon-virtual-dtor -I. -I./include -g -O3 -std=c++0x -g -O3 -std=c++0x -MT lib/rectangular_binary_matrix.lo -MD -MP -MF lib/.deps/rectangular_binary_matrix.Tpo -c lib/rectangular_binary_matrix.cc -DDLL_EXPORT -DPIC -o lib/.libs/rectangular_binary_matrix.o
so it doesn't look like it override the default include path. Any ideas?
p.s.
I was able to build the code on Linux (Redhat) without a problem.
posix_memalign is not part of the C Standard Library or the C++ Standard
library and the cygwin GCC compilers do not provide it, although other
compilers may do so, including GCC compilers from other builders.
You might consider using instead the C Standard function aligned_alloc, if you feel comfortable to edit your project source. It is provided in <cstdlib> for C++ compilation in cygwin g++ 6.4.0
Later
I do see the function in C:\cygwin64\usr\include\stdlib.h...
The fact that you can find the function declaration in the header file
does not mean that the compiler can see it after preprocessing. The same
source header may be used by many builders, exposing different
declarations to the compiler depending on the builder's settings of implementor
macros. In this case, the declaration is concealed from your compiler by
the fact that __POSIX_VISIBLE >= 200112 is false. Identifiers beginning __ are reserved for implementors.
See the explanation of this macro
and note the comment:
* The following private macros are used throughout the headers to control
* which symbols should be exposed. They are for internal use only, as
* indicated by the leading double underscore, and must never be used outside
* of these headers.
[SOLUTION FOUND]
Hello (I'm posting this on 2 threads regarding the same problem).
I'm here because I had the "POSIX_VISIBLE >= 200112" and the "posix_memalign was not declared in this scope" issue, which was halting the compilation of a program.
I'm not a programmer and tried various fixes on my own for a couple hours. Then finally Googled & came upon this site. The solutions here did not work for me, but I'll describe what did work:
The "posix_memalign" text was in a "stdlib.h" file that was being included into the code. The first problem was that in my "cygwin" directory, I have 25 instances of "stdlib.h"! Which one of those was being included?! I'm all new to this, but I finally found that
echo | gcc -E -Wp,-v -
might at least give an idea of which directory the files were being "included" from. This narrowed down the number of "stdlib.h" files to 4. Out of 4 such files, only one had the "posix_memalign" text. I tried changing the filename of that stdlib.h to see if it would cause an error--and confirm that it was the stdlib.h in question. However, this didn't effect the program. So I searched for a "stdlib.h" file in the next directory higher. THAT "stdlib.h" file also had the "POSIX" text in it. So when I changed THAT stdlib.h filename, the program DID error out. So that was the stdlib.h to deal with.
I saw that the "POSIX_VISIBLE >= 200112" instruction effected only the ONE line of code with "posix_memalign" in it. (In other words, the "POSIX_VISIBLE" instruction was not being used for the whole file.) I considered "commenting" it out, or deleting it. But then non-programmer me got the ingenious idea to simply change the ">=" to a "<". So I now had "POSIX_VISIBLE < 200112". I saved the file, ran the "configure" and "make" routine again, and boom, all was well. Program compiled properly.
Moral of the story, if you can determine the file (containing the POSIX statement and the posix_memalign) which is being accessed by your code, you may be able to solve your problem by just changing that one POSIX_VISIBLE operator as I did. (And you may want to switch that operator back after your compiling is done, in case that stdlib.h library file needs to be used by other programs in the future.)

g++ fails to link .o files into an executable

I am doing an example drill in the textbook I am using to learn from. All I need to do is compile, link and run the following 3 files:
//file my.h
extern int foo;
void print_foo();
void print(int);
my.h is a simple header file that declares the two functions and a 'global' int foo, with no initial value.
//file my.cpp
#include "my.h"
#include "std_lib_facilities.h" //not included but not source of error
void print_foo()
{
cout << foo << endl;
}
void print(int i)
{
cout << i << endl;
}
my.cpp contains the implementation of the functions included from my.h. std_lib_facilities.h is a file from the textbook, and is not the source of error (according to g++). I can edit it into the body of the question if needed.
//file use.cpp
#include "my.h"
#include <iostream>
int main() {
foo = 7;
print_foo();
print(99)
char cc; cin >> cc;
return 0;
}
use.cpp serves as the main implementation file in this program, and tries to use all three declared & defined objects.
I took the two step command approach to build using g++. First, I compiled both .cpp files:
g++ -c my.cpp use.cpp
which created two object files, my.o and use.o. I used the following command to link them:
g++ -o myprog my.o use.o
giving me this error:
Undefined symbols for architecture x86_64:
"_foo", referenced from:
print_foo() in my.o
_main in use.o
(maybe you meant: __Z9print_foov)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have tried putting
int foo;
into my.h instead of
extern int foo;
which gave me the same error.
I have tried using the
-std=c++11
flag as well which resulted in the same error.
I am using a MacBook Pro with the latest macOS (just updated in fact), if that helps with interpreting the error message.
I have tried to initialize foo, which didn't change anything.
In addition, I have tried updating the command line tools, same error.
From what I understand, the error is telling me that, even though my.h is included in both files, neither one can actually implement any function using the foo variable (which it calls _foo), despite it being explicitly declared in my.h. My guess is that the linker is using the wrong names under the hood, which make it impossible to link into an executable. This comes from the fact that the error mentioned a
__Z9print_foov
which exists nowhere in any of the files.
It almost seems like a g++ or macOS/Command Line Tools bug at this point. I don't want to add the declarations each time, because that creates duplicate symbol errors anyway. Putting my.cpp and use.cpp into one file would probably link properly, but I need to make sure that I can actually link multiple cpp files, because I will eventually (hopefully) be working with multiple cpp files that need to be linked. Any help is appreciated!
Here you declare a variable:
extern int foo;
and you use the variable:
cout << foo << endl;
but you did not define the variable anywhere. The linker error says that the linker could not find the variable's definition. To fix this, put int foo; at file scope in one of the .cpp files.
In the question you say that changing extern int foo; to int foo; gives the same error. However if you look more carefully at the error message I think you will find that it gives a different one, about multiple definitions.
I suggest to compile in two commands g++ -Wall -c my.cpp (that gives a my.o) and g++ -Wall -c use.cpp (giving use.o), then link a program with g++ my.o use.o -o myprog. Actually you should write a Makefile (see this for inspiration) and simply run make
Your translation units my.cpp and use.cpp are both declaring some extern int foo; variable which is never defined. So you need to define it in one single file (but not in others!), probably by adding (into my.cpp alone for example)
int foo;
(without the extern) or even with some explicit initial value e.g. int foo = 34;
This comes from the fact that the error mentioned a __Z9print_foov which exists nowhere
It is a mangled name, which is referenced (but not defined) in both object files (see also this).
It almost seems like a g++ or macOS/Command Line Tools bug at this point
You are very unlikely to find bugs in compiler tools (both GCC & Clang/LLVM are extremely well tested; since they are multi-million lines free software, they do have residual bugs, but you have more chances to win at the lottery than to be affected by a compiler bug). I'm coding since 1974, and it happened to me only once in my lifetime. A more realistic attitude is to be more humble, and question your own code (and knowledge) before suspecting the compiler or build chain.
BTW, always compile first with all warnings and debug info (e.g. g++ -Wall -g and perhaps also -Wextra). Use the gdb debugger. When you are convinced that your code has no bugs, you might benchmark it by asking the compiler to optimize (so use g++ -Wall -O2 perhaps also with -g to compile).
Read also the linker wikipage. Dive into your C++ textbook (see also this site and the C++11 standard, e.g. n3337 draft) to understand the difference between declaring and defining some variable or function. You generally declare a global extern variable in some common header (included in several translation units), and define it once somewhere else, but the good practice is to avoid having lots of global variables. See also C++17 new inline variables.