I compiled a library which use the g++ instead gcc. First I thought the source code was written in C++ but I found out later that there was not any C++ code in the *.cc files.
To confirm this, I replaced the g++ in the original makefile with gcc. And I still got the correct program.
Anyone can explain this? It was not the first time I met such a situation.
It depends on what exactly you changed in the makefile. gcc / g++ is really just a front-end driver program which invokes the actual compiler and / or linker based on the options you give it.
If you invoke the compiler as gcc:
it will compile as C or C++ based on the file extension (.c, or .cc / .cpp);
it will link as C, i.e. it will not pull in C++ libraries unless you specifically add additional arguments to do so.
If you invoke the compiler as g++:
it will compile as C++ regardless of whether or not the file extension is .c or .cc / .cpp;
it will link as C++, i.e. automatically pull in the standard C++ libraries.
(see the relevant bit of the GCC documentation).
Here's a simple program which detects whether or not it has been compiled as C or C++.
(It makes use of the fact that a character constant has the size of an int in C, or a char in C++. sizeof(char) is 1 by definition; sizeof(int) will generally be larger - unless you're using an obscure platform with >= 16-bit bytes, which you're probably not.)
I've called it test.c and copied it as test.cc as well:
$ cat test.c
#include <stdio.h>
int main(void)
{
printf("I was compiled as %s!\n", sizeof('a') == 1 ? "C++" : "C");
return 0;
}
$ cp test.c test.cc
$
Compiling and linking test.c with gcc, and test.cc with g++, works as expected:
$ gcc -o test test.c
$ ./test
I was compiled as C!
$ g++ -o test test.cc
$ ./test
I was compiled as C++!
$
Compiling and linking test.cc with gcc doesn't work: it compiles the code as C++ because the file ends in .cc, but fails at the link stage:
$ gcc -o test test.cc
/tmp/ccyb1he5.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
$
which we can prove by separately compiling with gcc, and linking with g++ (to pull in the right libraries):
$ gcc -c test.cc
$ g++ -o test test.o
$ ./test
I was compiled as C++!
$
...gcc has compiled the code as C++ rather than C, because it had a .cc file extension.
Whereas g++ does not compile .c files as plain C:
$ g++ -o test test.c
$ ./test
I was compiled as C++!
$
It could be that the .cc code happens to be C, but was intended to be linked into a C++ library. The internals are different.
g++ automatically links the C++ runtime library — gcc doesn't. Obvoiusly, when it doesn't matter — then it doesn't matter, but, as already pointed out by spraff, it could be intended for future use.
I don't know why they chose to use g++ instead of gcc, but I believe it shouldn't matter, as any valid C program is also valid C++.
Related
I am using Cygwin for my compiler while coding in Codeblocks IDE. Here is what I did in Cygwin 64:
$ gcc -std=c99
gcc: fatal error: no input files
compilation terminated.
However, it's not working. What is the proper way to do this?
To compile a c program in its simplest form to a certain standard, you can use the following command:
gcc -std=c99 -W -Wall main.c -o main
I am trying to generate LLVM bytecode file from a C source file (hello.c) using CMake. And below is my CMakeLists file.
###### CMakelists.txt ############
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_C_COMPILER "clang")
set(CMAKE_C_FLAGS "-emit-llvm")
project (hello)
add_executable(hello hello.c)
I am new to CMake and not sure if this is the right way. I could not find any rules to make *.bc in the generated MakeFile
. Please correct me here. I also tried "-save-temps"
Considering this for a single .c file. It would be really helpful if you could give me some hints on generating the same for a complete C project.
I think what you ultimately want is to be able to build a C-program
project with CMake and clang in which source files are compiled to LLVM bitcode
and the executable is linked from the bitcode files.
With CMake, asking clang to to link bitcode files means asking it to link in LTO mode,
with the -flto linkage option.
And you can get clang to compile to LLVM bitcode with the -flto compilation
option, or with the -emit-llvm option.
For illustration here is a Hello World project comprising two source files and one header:
$ ls -R
.:
CMakeLists.txt hello.c hello.h main.c
Here is the:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)
project (hello)
set(CMAKE_C_COMPILER clang)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-flto")
add_executable(hello main.c hello.c)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -flto)
#target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -emit-llvm)
It will work equally well with:
#target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -flto)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -emit-llvm)
Make a build directory for CMake and go there:
$ mkdir build
$ cd build
Generate the build system:
$ cmake ..
Build:
$ make
Scanning dependencies of target hello
[ 33%] Building C object CMakeFiles/hello.dir/main.c.o
[ 66%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello
You will not find any *.bc targets in the Makefiles, nor any *.bc files
generated:
$ egrep -r '.*\.bc'; echo Done
Done
$ find -name '*.bc'; echo Done
Done
because the compilation option -flto or -emit-llvm results in an output
file:
CMakeFiles/hello.dir/main.c.o
CMakeFiles/hello.dir/hello.c.o
that adheres to the usual CMake naming convention but is in fact not an object file
but an LLVM bitcode file, as you see:
$ file $(find -name '*.o')
./CMakeFiles/hello.dir/hello.c.o: LLVM IR bitcode
./CMakeFiles/hello.dir/main.c.o: LLVM IR bitcode
The program does the usual thing:
$ ./hello
Hello World!
Later
When I try " make hello.o " it should generate the object file right?
the cmd executes successfully but, could not find the generated object file. Am I doing it right?
You are doing it in one way that is right, though not the only way that is right, but
your expectations are wrong. Look again at:
$ file $(find -name '*.o')
./CMakeFiles/hello.dir/hello.c.o: LLVM IR bitcode
./CMakeFiles/hello.dir/main.c.o: LLVM IR bitcode
You can see there that the .o files that are made from hello.c and main.c
by the CMake-generated makefile are not called hello.o and main.o but hello.c.o
and main.c.o. CMake prefers a compiled filename to preserve the extension of the
source file, and append .o. That is a fairly common practice. So if you wanted
to use the makefile to compile hello.c, the most obviously right way would be
make hello.c.o.
Let's see what actually happens. In my CMake build directory:
$ make VERBOSE=1 hello.c.o
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/hello.c.o
make[1]: Entering directory '/home/imk/develop/so/scrap/build'
make[1]: 'CMakeFiles/hello.dir/hello.c.o' is up to date.
make[1]: Leaving directory '/home/imk/develop/so/scrap/build'
There was nothing to be done, because my hello.c.o was up to date. So I'll
delete it and repeat:
$ rm CMakeFiles/hello.dir/hello.c.o
$ make VERBOSE=1 hello.c.o
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/hello.c.o
make[1]: Entering directory '/home/imk/develop/so/scrap/build'
Building C object CMakeFiles/hello.dir/hello.c.o
clang -flto -o CMakeFiles/hello.dir/hello.c.o -c /home/imk/develop/so/scrap/hello.c
make[1]: Leaving directory '/home/imk/develop/so/scrap/build'
Now it has been recompiled.
However, because many people - like you - would expect hello.o to be compiled
from hello.c, CMake helpfully defines hello.o as a .PHONY target
that depends on hello.c.o:
$ egrep -A3 'hello.o.*:.*hello.c.o' Makefile
hello.o: hello.c.o
.PHONY : hello.o
So in fact I can do:
$ rm CMakeFiles/hello.dir/hello.c.o
$ make VERBOSE=1 hello.o
make -f CMakeFiles/hello.dir/build.make CMakeFiles/hello.dir/hello.c.o
make[1]: Entering directory '/home/imk/develop/so/scrap/build'
Building C object CMakeFiles/hello.dir/hello.c.o
clang -flto -o CMakeFiles/hello.dir/hello.c.o -c /home/imk/develop/so/scrap/hello.c
make[1]: Leaving directory '/home/imk/develop/so/scrap/build'
make hello.o is another way of making hello.c.o
The problem is that using the -emit-llvm flag does not produce a final binary and stops the configuration tests that CMake performs once that flag is used in them.
Apart from what's already been written about using the LTO infrastructure, you have 3 (or 2 and a half) other alternatives.
One is to use Whole-Program LLVM and use the commands provided to extract the relevant bitcode parts.
The other is to go the manual way of setting up custom targets (see add_custom_target and add_custom_command) on your CMake binary targets, that will get triggered on changes and will reproduce the desired outcome as if executed manually on the command line each time.
Now, on this last point, I had a similar need so I created a CMake project that provides that functionality (llvm-ir-cmake-utils), but allows you to hook up those custom targets on existing ones as you please and see fit without having to rewrite everything from scratch each time.
There are examples in the repo, but in short, it allows you to attach custom targets on already existing CMake targets, e.g.
[...]
add_executable(qux ${SOURCES})
[...]
# this will create a bitcode generating target
# and allow it to depend on the initial target in order to detect source code changes
llvmir_attach_bc_target(qux_bc qux)
add_dependencies(qux_bc qux)
[...]
After make,
$>file CMakeFiles/hello.dir/hello.c.o
CMakeFiles/hello.dir/hello.c.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
if
set(CMAKE_C_FLAGS "-emit-llvm")
written before
project (hello)
In order to obtain IR bitcode, I wrote:
###### CMakelists.txt ############
cmake_minimum_required(VERSION 2.8.9)
project (hello)
set(CMAKE_C_COMPILER "clang")
set(CMAKE_C_FLAGS "-flto")
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-flto")
add_executable(hello hello.c)
target_compile_options(hello PUBLIC ${CMAKE_C_FLAGS} -flto)
I worked several hours in order to have a Makefile working to compile from IR
code to native using lld, then with cmake it was much more faster.
Then reading at cmake generated Makefile, I was able to correct my Makefile:
clang -flto -flto <hello.c.o> ..
this worked but I do not know why -flto is written twice.
Thanl you very much for this post, showing clang as the centralized front end to various llvm provided commands.
I'm getting started with multi-thread programming using gcc under Debian 8. I've successfully written and run a multi-threaded test app (foobar.c), but I'm confused by the Makefile (copied from an example). In particular, the command that works is
gcc foobar.c -o foobar -pthread
I'm confused by "-pthread". is that
(a) an option "-p" with value "thread", or
(b) an argument "-pthread" ?
if either case, what is it actually doing? Including some library? Including some object? Setting some other option?
BTW - A similar question 15929739 was asked but never answered. Question 20924412 was not helpful either.
From the man page:
-pthread
Adds support for multithreading with the pthreads library. This option sets flags for both the preprocessor and linker.
To be specific, as of GCC 6.2.1, -pthread will:
#define _REENTRANT 1
Add -lpthread to link against libpthread
How do I know this, you ask?
What preprocessor flags are added?
Let's dump the preprocessor defines and compare them:
$ diff <(gcc -dM -E - < /dev/null) <(gcc -pthread -dM -E - < /dev/null)
> #define _REENTRANT 1
What linker options are added?
Let's dump the ld options passed by GCC and compare them:
diff <(gcc -### -o foo empty.c 2>&1) <(gcc -### -pthread -o foo empty.c 2>&1)
The output here is a bit more verbose, but if we ignore the temporary filename differences, we find:
-lpthread
"-plugin-opt=-pass-through=-lpthread"
I have a fairly complex scons system with several subdirectories, with many libraries and executables.
Currently, every SConscript gets its own cloned environment, so I can easily change CFLAGS (or any other wariable) on a per-SConscript basis, but I'd like to change it per-target, and even per-object-file within a target.
I created a simple example SConscript and SConstruct to explain the problem, as follows.
SConstruct:
env = Environment()
env['CFLAGS'] = '-O2'
env.SConscript('SConscript', 'env')
SConscript:
Import('env')
env=env.Clone()
env.Program('foo', ['foo.c', 'bar.c'])
If I run scons, both foo.c and bar.c compile with -O2 flags. I could easily change flags SConscript-wide by just adding env['CFLAGS'] = '...' within the SConscript, but let's say that I want to compile foo.c with -O2, but bar.c with full debugging, -O0 -g. How do I do that (in the simplest possible way)?
The example uses gcc, but I'd like something that can be used with any compiler.
This happens frequently with performance-sensitive projects where compiling everything without optimization would result in unacceptable performance, but there is a need to debug one single file (or a subset of them).
The simplest one-liner answer is probably just to replace your Program line with this:
env.Program('foo', ['foo.c', env.Object('bar.c', CFLAGS='-g')])
because Program can take Object nodes as well as source files, and you can override any construction variable(s) in any builder (here, we override CFLAGS in the Object builder call). If you want to break out the Object into its own line for clarity:
debug_objs = env.Object('bar.c', CFLAGS='-g')
env.Program('foo', ['foo.c', debug_objs])
and of course taking that to the limit you get a system like Avatar33 showed above.
I suppose this is a bit harder in scons than it would be in make where you could just clean the required target and rebuilt with debug flags. Which would then just rebuild a specific object.
The solution to your particular project depends on it's size and how much effort the developer is prepared to put in.
So here's a rough solution where you specify source files on the command line that you want to be compiled with debug and no optimization, the rest will be compiled with -O2.
In your SConsctruct one additional line to get source files that we want to compile with debug from a command line option:
env = Environment()
env['CFLAGS'] = '-O2'
AddOption('--debug-targets', dest='debug-targets', type='string')
env.SConscript('SConscript', 'env')
And now in the SConscript file:
Import('env')
env=env.Clone()
debug_env = env.Clone()
debug_env['CFLAGS'] = '-g -O0'
normal_src = ['foo.c', 'bar.c']
debug_src = []
#Add src specified via the command line to the debug build
if GetOption('debug-targets'):
for x in GetOption('debug-targets').split(','):
if x in normal_src:
normal_src.remove(x)
debug_src.append(x)
normal_obj = env.Object(normal_src)
debug_obj = debug_env.Object(debug_src)
all_obj = normal_obj + debug_obj
env.Program('foo', all_obj)
Running our scons with out our debug-targets flag:
scons -Q
gcc -o bar.o -c -O2 bar.c
gcc -o foo.o -c -O2 foo.c
gcc -o foo foo.o bar.o
But now we want to compile bar.c with debug info:
scons -Q --debug-targets=bar.c
gcc -o bar.o -c -g -O0 bar.c
gcc -o foo foo.o bar.o
So that adds a bit of complexity to your build system, but if you don't need to specify debug targets from the command line like that, then the developer can obviously just cut and past sources from the normal_src list to debug_src.
There's probably many ways to improve and fine tune this for your specific environment
I'm a dumb newbie.
I've got a file named file.c with the functions my_putstr(char *) and my_strlen(char *)
my_putstr() writes the parameter with write() (unistd.h)
I wanted to create a library from file.c so I did :
gcc -fPIC -c file.c
gcc -shared -o libfile.so file.o
Then I created a main.c file and called my_putstr() from it.
I tried to compile and link my .so
gcc -L. -lfile main.c -o test
But I got an undefined reference to my_putstr()
I tried to create a .h with my_putstr() and my_strlen() in it, and include it to the main but I got the same error.
Sorry for stupid questions.
Havaniceday.
Your question suffers lack of information, but I can suggest you at first try
gcc main.c ./libfile.so -Wl,-rpath . -o test
If this will fail, you have something wrong with your sources.
If everything is ok at this point, then try
gcc main.c -L . -lfile -Wl,-rpath . -o test
If this will output undefined reference, then probably you already have something like libfile.a without my_putstr(may be from previous experiments) in your lib path.
If everything is ok with it, then your linker is sensible to order in which libraries is supplied to command string, and you must remember, then library always comes after object, that uses this library.