How to use precompiled headers with gcc if linking against openmp - gcc

Minimal example:
// file: main.cpp
#include "pch.h"
int main()
{
std::cout << "test" << std::endl;
return 0;
}
--
// file: pch.h
#include <iostream>
Works fine and as expected if I compile this with
g++ pch.h
g++ main.cpp -Winvalid-pch
However once I change the last line to:
g++ main.cpp -fopenmp -Winvalid-pch
usage of the precompiled header is disabled:
warning: pch.h.gch: not used because `_REENTRANT' is defined [-Winvalid-pch]
How can I still use precompiled headers while linking to OpenMP? Why does the _REENTRANT define conflict with using a precompiled header at all?

You must generate .pch and compile sources with identical flags. -fopenmp implies #pragma omp and -pthread.
g++ -fopenmp pch.h
g++ main.cpp -fopenmp -Winvalid-pch
Or at least
g++ -pthread pch.h
g++ main.cpp -fopenmp -Winvalid-pch

Related

Make - what files do I need to state as prerequisites for a target with multiple #include statements?

Assuming I have this example.h:
// example.h
#include "a.h"
#include "b.h"
#include "c.h"
#include "d.h"
#include "e.h"
And example.c:
// example.c
#include "example.h"
#include "a.h"
#include "b.h"
#include "c.h"
#include "d.h"
#include "e.h"
Should my Makefile look like this? :
example.o : example.h example.c
gcc -c example.c -o example.o
Or should it look like this? :
example.o : example.h example.c a.h b.h c.h d.h e.h
gcc -c example.c -o example.o
1) It should look like your second version:
example.o : example.h example.c a.h b.h c.h d.h e.h
gcc -c example.c -o example.o
2) There is no reason for the same #include statement to appear in both example.h and example.c, and redundant #include statements are kruft and ought to be removed. For safety, put them in example.h; for efficiency, put them in example.c when you can. (I won't go into the details of when you can here, but the compiler will tell you when you get it wrong.)
3) If you don't want to maintain that list of headers in the makefile, gcc and Make can take care of it for you. Here's an example, but this is an advanced technique, so I advise you not to use it until you understand how it works:
example.o : example.c
gcc -MMD -c example.c -o example.o
-include *.d

-fopenmp flag in compile and link

I have this openmp code
#include <omp.h>
#include <stdio.h>
int main()
{
#pragma omp parallel
{
fprintf(stderr, "thread %d\n", omp_get_thread_num());
}
return 0;
}
when I compile and link and use the -fopenmp
gcc-6 -std=c99 -Wall -Wextra -pedantic -fopenmp -Iinclude -c -o build/main.o src/main.c
gcc-6 -o bin/main build/main.o -fopenmp
the code work
$ ./bin/main
thread 0
thread 1
thread 2
thread 3
but don't when I only put the flag in the link
gcc-6 -std=c99 -Wall -Wextra -pedantic -Iinclude -c -o build/main.o src/main.c
src/main.c: In function 'main':
src/main.c:6:0: warning: ignoring #pragma omp parallel [-Wunknown-pragmas]
#pragma omp parallel
gcc-6 -o bin/main build/main.o -fopenmp
the code work but not in parallel
$ ./bin/main
thread 0
why I need add -fopenmp in compile and link time?
why I need add -fopenmp in compile and link time?
Because it is required both at compile time (to enable the #pragma omp handling) and at link time (to link required support libraries).

linking OpenMP statically with GCC

Given the following file print.cpp
#include <stdio.h>
int main() {
printf("asdf\n");
}
I can link this statically like this
g++ -static print.cpp
or like this
g++ -static-libgcc -Wl,-Bstatic -lc print.cpp -o print
But now let's add a little OpenMP and call the file print_omp.cpp
#include <omp.h>
#include <stdio.h>
int main() {
printf("%d\n", omp_get_num_threads());
}
I can link this statically like this (I checked it with ldd)
g++ -fopenmp -static print_omp.cpp
However, this does not work
g++ -fopenmp -static-libgcc -Wl,-Bstatic -lc print_omp.cpp -o print
I have tried various combinations of -Wl,--whole-archive -lpthread -Wl,--no-whole-archive and -lgomp -lpthread but no luck (I get various problems linking to pthreads). Can someone explain how I can do this without using the -static option?
GCC says
On glibc-based systems, OpenMP enabled applications cannot be statically linked due to limitations of the underlying pthreads-implementation
However, since g++ -fopenmp -static print_omp.cpp works just fine this does not make sense to me.
Edit:
I figured this out. The library GOMP comes with GCC whereas pthreads and libc come from GLIBC. So I can link GOMP statically like this
ln -s `g++ -print-file-name=libgomp.a`
g++ foo.cpp -static-libgcc -static-libstdc++ -L. -o foo -O3 -fopenmp
ldd shows
linux-vdso.so.1 => (0x00007fff71dbe000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc231923000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc23155c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc231b5c000)
However, if I the try this
ln -s `g++ -print-file-name=libpthread.a`
g++ foo.cpp -static-libgcc -static-libstdc++ -L. -o foo -O3 -fopenmp
It won't link. Pthreads and libc must be linked statically together. So once I add
ln -s `g++ -print-file-name=libc.a`
g++ foo.cpp -static-libgcc -static-libstdc++ -L. -o foo -O3 -fopenmp
ldd returns
not a dynamic executable
I really don't get why you may want to link only libgomp statically, but having separate compilation and linking commands may help. For instance assume main.cpp contains:
#include <omp.h>
#include <stdio.h>
int main() {
#pragma omp parallel
{
printf("%d\n", omp_get_thread_num());
}
}
Then:
~/tmp$ ls
main.cpp
~/tmp$ g++ -Wall -Werror -pedantic -fopenmp main.cpp -c
~/tmp$ ls
main.cpp main.o
~/tmp$ locate libgomp.a
${SOME_PATH_TO_LIBGOMP}/libgomp.a
~/tmp$ g++ -Wall -Werror -pedantic main.o -o main.x ${SOME_PATH_TO_LIBGOMP}/libgomp.a -pthread
~/tmp$ ls
main.cpp main.o main.x
~/tmp$ ldd main.x
linux-gate.so.1 => (0xb7747000)
libstdc++.so.6 => /production/install/gnu/compiler/gcc/lib/libstdc++.so.6 (0xb765c000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb75fa000)
libgcc_s.so.1 => /production/install/gnu/compiler/gcc/lib/libgcc_s.so.1 (0xb75de000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb75c2000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7413000)
/lib/ld-linux.so.2 (0xb7748000)
The most clean solution I've found for this is by modifying the libgomp.spec. Mine is at /usr/local/lib64/libgomp.spec. Change the content as follow:
*link_gomp: -l:libgomp.a %{static: -ldl }

while build a demo about ffmpeg , it occurs : undefined reference to `av_register_all'

This problem has bothered me for days.
After I compile and install ffmpeg , I try to build a demo using it, but it always fails.
The demo is:
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
int main(int argc,char *argv[]) {
av_register_all();
return 1;
}
With gcc main.c -o main.o, an error occurs: undefined reference to 'av_register_all'
Building with: gcc main.c -o main.o -lm -ld -lz -lavcodec -lavformat -lavutil, another error occurs: /usr/bin/ld: cannot find -ld
How can I resolve this?
Putting includes within extern "C" block may work.
extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
As mentioned here
the order of libraries matters
so in your case the following hopefully should work:
gcc main.c -o main.o -lavformat -lavcodec -lavutil -lz -lm -lpthread
gcc filename.c -o outputfilename -lavformat -lavcodec -lavutil -lz -lm -lpthread -I'/usr/local/include' -lswresample
The above command will help to compile properly.
Have a look at how this project builds sample code.
The Makefile is pretty simple to follow.
It's work for me:
gcc <your source code> -o main -lavformat -lavcodec -lavutil -lm -lpthread -I'/usr/local/include' -lswresample

g++ : include problems when cross compiling

I've got a problem that's a bit strange.
We have a project that we compile for several different architectures, notably these 2: SH4 and MIPS.
We've had a problem for some time, where some code would compile in SH4, but not for MIPS, because of missing includes. I've narrowed down the problem to this test file:
#include <sstream>
// deliberately not including the needed includes
int main()
{
const char *toto = "Hello World";
// using printf and strlen which require <stdio.h> and <string.h>
printf("Toto has len %d\n", strlen(toto));
return 0;
}
Compiling to SH4 with this command
$ sh4-linux-g++ -O0 -g -Wall -Werror -Wno-write-strings \
-fno-rtti -fno-exceptions test.cpp -o test
$
-> no problem at all. The file actually executes normally.
Whereas with MIPS
$ mips-linux-gnu-g++ -O0 -g -Wall -Werror -Wno-write-strings \
-fno-rtti -fno-exceptions test.cpp -o test
test.cpp: In function 'int main()':
test.cpp:6: error: 'strlen' was not declared in this scope
$
Now, I've run several things, notably the dependency generation of both g++. What I see is this:
SH4 
$ sh4-linux-g++ -O0 -g -Wall -Werror -Wno-write-strings \
-fno-rtti -fno-exceptions test.cpp -M |grep "/string.h"
/opt/STM/STLinux-2.3/devkit/sh4/target/usr/include/string.h \
-> string.h automatically included.
MIPS
mips-linux-gnu-g++ -O0 -g -Wall -Werror -Wno-write-strings \
-fno-rtti -fno-exceptions test.cpp -M |grep "/string.h"
-> string.h missing in includes
For information:
SH4 version = 4.2.4 (2007)
MIPS version = 4.3.2 (2008)
What's going on here? The <sstream> include seems to drag along all what's needed for strlen() when compiling on SH4, whereas on MIPS it doesn't. I suspect this is because the versions are different, but I'm not sure.
My real problem, in the end, is that when I develop on SH4, I'd like to be sure that if it compiles, it will compile on all targets.
Is there a solution to this?
What's going on here?
You're basically asking "why does my non-standard code compile with one version of a compiler but not another?" Of course it's because the versions are different.
See the GCC 4.3 changes which say this under the Runtime Library (libstdc++) section:
Header dependencies have been streamlined, reducing unnecessary includes and pre-processed bloat.
We've continued reducing header dependencies in more recent versions too, to be stricter and to reduce namespace pollution (e.g. 4.6 avoids including <cstddef> unnecessarily, and 4.7 no longer includes <unistd.h> unnecessarily), so to answer your final question I would suggest using the most recent GCC version you can (even if only to check the code not for production builds) as it has the strictest, cleanest headers and will find the most problems. Another option would be to use an even stricter standard library implementation, such as libcomo.

Resources