NVCC linking error in C and CUDA-C code - c

I'm working on an DNA Fragment Assembly program. The CPU-only version is built in C language using GCC and I'm trying to build a GPU version using NVCC.
Here is the makefile
all : clean FragmentAssembly.exe
FragmentAssembly.exe : Common.o Fragment.o ILS.o Consensus.o main.o
nvcc -pg -o FragmentAssembly.exe Common.o Fragment.o ILS.o Consensus.o main.o
Common.o : Common.cu
nvcc -pg -o Common.o -c Common.cu
Fragment.o : Fragment.cu
nvcc -pg -o Fragment.o -c Fragment.cu
ILS.o : ILS.cu
nvcc -pg -o ILS.o -c ILS.cu
Consensus.o : Consensus.cu
nvcc -pg -o Consensus.o -c Consensus.cu
main.o : main.cu
nvcc -pg -o main.o -c main.cu
clean :
rm -f *.exe *.o
As seen, the original .c files became .cu files for nvcc to compile them correctly.
All of the cu files contain includes of their corresponding files (Common.h for Common.cu, etc..) except for main.cu.
ILS.h contians definition of global variables p_instanceFragments and p_instanceLength
The problem is when compiling NVCC, for an unknown reason, I get the following errors :
Consensus.o:(.bss+0x0): multiple definition of `p_instanceFragments'
ILS.o:(.bss+0x0): first defined here
Consensus.o:(.bss+0x8): multiple definition of `p_instanceLength'
ILS.o:(.bss+0x8): first defined here
There is no real multiple definitions since the same code is built correctly using GCC. It looks as if ILS.h is getting included twice in nvcc, by ILS.cu and Consensus.cu. This is also not possible since I've wrapped all my header files with an #ifndef .. #define .. #endif statements to avoid multiple includes and infinite include loops.
Maybe something with the makefile commands ? or should I use gcc for linking ? Can you tell me how to deal with it ?
Regards,

After discussion: Here a description of what happened:
If you use gcc and you have two files (lets say f1.c and f2.c), and in both files you declare:
int myGlobalVariable;
Then the following will happen:
When compiling f1.c into f1.o, the object file will reserve space for myGlobalVariable.
When compiling f2.c into f2.o, the object file will also reserve space for myGlobalVariable.
When you link both object files together, the linker will detect that there are two variables called myGlobalVariable and will merge these variables together.
Now it seems the nvcc compiler/linker is not able to merge these variables.
The problem was, that the file ILS.h declares <some type> p_instanceFragments;. Because ILS.h is included into both ILS.cu and Consensus.cu, you get this variable twice and nvcc complains when it has to link the application.
The solution is to declare extern <some type> p_instanceFragments; in ILS.h and then to define <some type> p_instanceFragments; either in ILS.cu or Consensus.cu (not in both).
The question What are extern variables in C has a rather extensive answer explaining all of this in detail.

Related

C how to use library with multiple header tree

I am not understanding how I should compile with gcc the following .c and library.
example:
Files: "commons.h" and "commons.c" (the .c defines function etc...)
Files: "level1.h" and "level1.c", level1.c includes "commons.h"
Files: "level2.h" and "level2.c", level2.c includes "commons.h" and "level1.h"
I tried this and got "undefined reference to x" (where x is a function inside level1):
gcc commons.c -c -o commons.o (OK)
gcc level1.c -c -o level1.o (OK)
gcc level2.c -o level2.o (error, undefined reference to x)
I expect to have level2 to be execute, I will only execute this.
How should I compile? Which order? (an example with command line will help me understand)
Your last line should also use the -c flag in order to compile level2.c to an object file level2.o.
Afterwards the object files should be linked to create an executable, which is done via
gcc common.o level1.o level2.o -o my_executable
Alternatively you can directly supply all the source files to gcc without the -c flag, in which case it will perform all of the compilation and linking steps at once:
gcc common.c level1.c level2.c -o my_executable
Your error is currently caused, because you are instructing gcc without the -c option to compile and link the source file level2.c alone, but of course it can not be linked alone as it is missing symbols from the other source files.
The fact that level2.c contains main does not change anything about this. main is handled like any other function, only that it has a special meaning in the final executable as entry point.

Why is my very simple makefile not working

When I say very simple I mean it. I have a main.c and a header file called input_error.h.
main.o : main.c input_error.h
gcc -c main.c
When I run the command "make" gcc -c main.c is executed but it's not updating any changes I make to my main.c file. When I manually type in "gcc main.c" it works fine.
EDIT: It seems like I need to add another rule but I'm not sure what that entails
At the moment your makefile only builds the .o file. You can build your binary in 2 ways. Note that make requires the indentation in the targets statements to be a tab and not 4 spaces, as it may have been converted to by the browser.
build .o separately then link binary. Note that using the -c switch causes gcc to build only the object file.
main: main.o
gcc main.o -o main
main.o : main.c input_error.h
gcc -c main.c -o main.o
build in one step
main: main.c input_error.h
gcc main.c -o main
You can also avoid repetition in your makefile by using special variables to denote the target ($#), the first dependency ($<) and all (#^) the dependencies.
e.g. one of the above lines could become
main.o : main.c input_error.h
gcc -c $< -o $#
Which seems a bit cryptic at first but you get used it. The implicit rules in #kaylums answer will also help to cut down on typing.
The Makefile you have only has a single rule to compile the .o file. That is, it does not have any rule to link the final executable.
make has implicit rules for building many common targets. So your Makefile could be as simple as the following:
all: main
main.o : input_error.h
For further explanation:
all: main: Since this is the first target it is the one that will be built by default if no explicit target is provided to the make command line. It depends on a single target main.
There is no explicit rule for main but make has an implicit rule which will build it from main.c.
main.o : input_error.h: Tells make that main.o needs to be rebuilt if input_error.h changes. There is no need to put main.c here as make has that implicit knowledge. There is also no need for an explicit command as make also has that implicit.

compile multiple source file in c

I have written c program, Which has 3 file(.c ) , Main program has
two threads and one file has mysql connection function, One file has
thread functions definition. I don't know how to compile all these
codes, Normally I tried like this,
cc -pthread main.c
But if I compile like this I am getting error called mysql functions
are undefined But I have written thread as separate program and
mysql as separate program and complied individually , it complied
successfully and I got output. So please help me to compile my
project File names are,
main.c (2 threads are declared) functions.c (thread function
definition, and mysql func declared) db.c ( mysql function
definition)
please help to compile my code?
You have two basic options when compiling multiple .c files:
Option 1)
cc file1.c file2.c file3.c -o executable_name
Advantage: simple
Disadvantage: if all you change is one file you are recompiling all the files
Option 2)
cc file1.c -c -o file1.o
cc file2.c -c -o file2.o
cc file3.c -c -o file3.o
cc file1.o file2.o file3.o -o executable_name
Advantage: If you change one file you do not have to recompile everything
Disadvantage: Multiple commands (but you should use a Makefile at this point)
The -c flag tells the compiler to compiler but not link. You don't want to link as you have not compiled all of your files. The final invocation of cc links all the .o files into the executable executable_name
It is a little bit difficult to understand exactly what you need, but I can tell you from what you've stated that you'll need to include specific libraries in your compile statement you currently are not. Also, a -l flag needs to prefix your libraries.
Try something like this:
gcc -lpthread main.c functions.c db.c -o main $(mysql_config --libs)
To explain, mysql_config --libs returns all the configuration libraries needed to run mysql ddl inside your C program.
Given your updates on your file declarations I'm guessing you're a Java programmer. C is not Java. If you are declaring functions you are only going to use once in main.c you should put them inside main.c unless you need them to be portable.

using a method from another file without including it [duplicate]

This question already has answers here:
Why is #include <stdio.h> not required to use printf()?
(3 answers)
Closed 8 years ago.
I have two .c files which I compile over a makefile.
foo.c:
void foo()
{
printf("this is foo");
}
main.c:
#include <stdio.h>
int main()
{
printf("this is main\n");
foo();
}
the makefile looks like that:
all: main.o foo.o
gcc -o prog foo.o main.o
main.o: main.c
gcc -c main.c
foo.o: foo.c
gcc -c foo.c
So the question is:
how can foo.c use printf() without me including stdio.h AND how can main.c use the method foo() without me including foo.c.
My guess/research is that the makefile works as a linker. But I dont have prove for that and want to understand how this works excactly.
Correct me if I misunderstood something.
In the compilation phase, the compiler checks function calls against prototypes. Any function that lacks a prototype is assumed to return int and to accept any number of arguments.
If you turn up the warning level, gcc will warn you if a prototype is missing. You should add -Wall and you could also add -pedantic to get diagnostics on additional things the compiler think are suspicious.
If the compilation step succeeds, the compiler creates an object file which contains the compiled code and 2 reference tables. The first table is the export table. It contains the names of all functions and variables that are exported from the object file.
The second table is the import table. It contains a list of all functions and variables that are referenced, but where the declaration was missing.
In your case we have:
foo.o:
Export:
foo
Import:
printf
main.o
Export:
main
Import:
printf
foo
In the linker phase, the linker will take the list of imports and exports and match them. In addition to the object files and libraries you specify on the command line, the linker will automatically link with libc, which contains all functions defined by the c language.
In the makefile you can force the complier to include <stdio> or any other header:
From the docs:
-include file
Process file as if #include "file" appeared as the first line of the
primary source file. However, the first directory searched for file is
the preprocessor's working directory instead of the directory
containing the main source file. If not found there, it is searched
for in the remainder of the #include "..." search chain as normal. If
multiple -include options are given, the files are included in the
order they appear on the command line.
Just add -include filename.h in the GCC/compiler command line within the makefile.
The makefile is not a linker. It is input to make. The makefile just tells make what commands to execute under what conditions.
Your all target is running gcc in linking/linker mode gcc -o prog foo.o main.o.
The same way your foo.o and main.o targets are running gcc in compilation mode gcc -c foo.c.
For the record you can combine the two .o targets into just
%.o: %.c
gcc -c $^
which is, in fact, already a default rule in make so you need not include that rule at all.
Additionally your all target is not following bet make practices because it generates a file that does not match the name of the target. So you should use
all: prog
prog: main.o foo.o
gcc -o prog foo.o main.o
instead.
Though once again there make has you covered by default and so your entire makefile can be replaced by
all: prog
prog: main.o foo.o
and you should get the same results.

NVCC refuses to link my object files

I am trying to compile a project by compiling object files and then linking them together, nothing fancy:
hello.o : hello.h hello.cu
nvcc hello.cu -c -o hello.o
#...
main.o : $(objs)
nvcc *.o -o exec
When I get to the link phase, just about every method is shown to be missing and undeclared, despite the fact that nm shows that each is in fact sitting within my object files, and their names are unmangled. What is going on here?
Your final make target looks bogus: shouldn't it say:
exec : $(objs)
nvcc $(objs) -o $#
You may also need to add the CUDA libraries to the command-line (I think nvcc figures this out when you're compiling a .cu file directly, but maybe it doesn't if you just give it .o files). So, something more like this:
exec : $(objs)
nvcc $(objs) -o $# -lcuda -lcudart -lcublas
(Precisely which libraries you need depends on your code)
Ok, so my question's formulation was incorrect. In fact, the problem was that I was compiling C code like so:
hello.o : hello.h hello.cu
nvcc hello.c -c -o hello.o
#...
main.o : $(objs)
nvcc *.o -o exec
which caused nvcc to pass the .c files to gcc. When I grepped 'nm *.o' for the name of my method, I found that the object files emitted by gcc had unmangled names, while the .cu files, which were compiled by g++, expected mangled names.
My solution was to rename all the .c files in my project to .cu, although I think (but haven't tested) that leaving them as .c and calling g++ on them explicitly in the makefile should be enough.
I tried calling g++ but still got the same errors. The answer was found here:
http://forums.nvidia.com/index.php?showtopic=190973&st=0&gopid=1179661&#entry1179661
In short, function prototypes need to be correct.

Resources