GCC Compiler Refuses To See Main Method (C Programming) - c

I recently downloaded the AGIL adventure game interpreter from: http://www.agidev.com/dl_files/agil-0.1.5.tar.gz
It is a C program which runs old Sierra adventure games like King's Quest.
I have being trying to compile the source code so that I can debug it and learn how it works.
However despite my best efforts the GCC compiler never sees the main method, despite its existence.
Here is the compiler output:
make linsdl all
make -fMakefile.sdl
make[1]: Entering directory `/home/alay/Downloads/AGIL/agil'
gcc -O -Wall -Isrc/include -I/usr/local/include -DTARGET_SDL -fstrength-reduce -fomit-frame-pointer -pedantic -I/usr/local/include/SDL -Dmain=SDL_main -c src/main.c -o bin/main.o
gcc -O -Wall -Isrc/include -I/usr/local/include -DTARGET_SDL -fstrength-reduce -fomit-frame-pointer -pedantic -I/usr/local/include/SDL -Dmain=SDL_main -c src/drivers/sdl.c -o bin/driver.o
gcc -L/usr/local/lib bin/main.o bin/general.o bin/event.o bin/graphics.o bin/menu.o bin/text.o bin/resource.o bin/gameid.o bin/pic_op.o bin/picture.o bin/lzw.o bin/vm.o bin/actionop.o bin/testop.o bin/status.o bin/object.o bin/view.o bin/check.o bin/save.o bin/message.o bin/sound.o bin/decomp.o bin/driver.o \
-o bin/agil -lm -lSDLmain -lSDL -lpthread
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o: In function `_start':
make[1]: Leaving directory `/home/alay/Downloads/AGIL/agil'
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
make[1]: *** [all] Error 1
make: *** [linsdl] Error 2
The only changes I made were to change include statements so that the compiler could find the SDL library. For example I changed: #include "SDL.h" to #include "SDL/SDL.h".
My goal is to understand the C code so that I can build something similar on another platform.

The -Dmain=SDL_main is equivalent to having a #define main SDL_main in your code. The preprocessor will replace the main with SDL_main, and the linker won't find it ( because it itn't there).
Run gcc -E ... and see how the code looks after the preprocessor ran, but before it goes to the compiler.
LE: True. But I wouldn't pass it as argument to gcc ( and changing the header files ). But it as a define after the includes.
Also run a locate libsdl and check you pass the path correctly to the linker.

Related

undefined reference to `le16toh' error in Makefile

I'm trying to compile a C program with the following Makefile:
msh: libFAT32.so
gcc -Wall -fPIC -I. -o msh newTest.c -L. -lFAT32
libFAT32.so:
gcc -std=c99 -shared -o libFAT32.so -fPIC fat32.c
clean:
rm *.so msh
However, every time I try to compile the program with make I get the following error:
user#user-VirtualBox:~/fat1$ make
gcc -Wall -fPIC -I. -o msh newTest.c -L. -lFAT32
./libFAT32.so: undefined reference to `le32toh'
./libFAT32.so: undefined reference to `le16toh'
collect2: error: ld returned 1 exit status
Makefile:19: recipe for target 'msh' failed
make: *** [msh] Error 1
Can some one tell how to fix this?
So, here's what's going on (making the safe assumption that you're using a linux distribution in your VM).
With this test program:
#include <stdio.h>
#include <endian.h>
int main(void) {
printf("%d\n", le32toh(1234));
return 0;
}
compiling and running it works:
$ gcc -Wall -Wextra test.c
$ ./a.out
1234
However, you're compiling using -std=c99. So let's try that:
$ gcc -std=c99 -Wall -Wextra test.c
test.c: In function ‘main’:
test.c:5:18: warning: implicit declaration of function ‘le32toh’ [-Wimplicit-function-declaration]
printf("%d\n", le32toh(1234));
^~~~~~~
/tmp/cc7p3cO8.o: In function `main':
test.c:(.text+0xf): undefined reference to `le32toh'
collect2: error: ld returned 1 exit status
Compiling in c99 mode disables a bunch of functions and macros and such that aren't in the 1999 version of the C standard unless they're explicitly requested, hence the implicit declaration warning. le32toh() is a macro, not a function with a symbol in libc, hence the linker error.
If you read the man page for le32toh(), you'll see that it needs the _DEFAULT_SOURCE feature test macro, which must be defined before any headers are included.
So, your options are:
Compile in gnu99 mode instead, since that automatically defines a bunch of the feature test macros.
Continue to use c99 mode and add a #define _DEFAULT_SOURCE at the very start of your fat32.c source file.
Continue to use c99 mode and add -D_DEFAULT_SOURCE to your compiler arguments.

Linking 2 object files in c to create an executable

I am having an issue with a makefile for something I am making. My makefile looks like this
bag: main.o bow.o
gcc bow.o main.o -o bag
main.o: main.c bow.h
gcc -Wall -ansi -pedantic main.c -o main.o
bow.o: bow.c bow.h
gcc -Wall -ansi -pedantic -c bow.c -o -bow.o
I also have a header file called "bow.h" that is used in both bow.o and main.o. bow.h consists of 8 function definitions and 2 structs, bow.c contains the 8 functions and NO MAIN file. main.c is suppose to be a minimal main file so it only consists of
#include "bow.h"
When I run my makefile in the Terminal with
make
I get this message
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
makefile:2: recipe for target 'bag' failed
make: *** [bag] Error 1
What exactly does this mean, how is it caused and how can I fix it?
Even a minimal program (executable) needs a point to start. For a C program, this is the main() function. Thus, the linker seeks for that function (more precisely, it links the start-up object where main is an unresolved symbol), does not find it, and issues an error.
Thus, you have to provide a main(). Alternatively, you may not generate an executable but a library.

Cannot find -lCommunication collect2: error: ld returned 1 exit status

I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main

C Makefile error: ld returned 1 exit

My teacher is not the best at explain C so I'm having a bit of trouble understanding the connection of makefiles. I have already added the code for complex.c, complex.h, and main.c. I'm just having trouble compiling it all using the make command. I followed the example on the powerpoint he handed up and I don't understand why its failing to get to complex.
makefile
complex: main.o complex.o
gcc -o complex main.o complex.o
main.o: main.c complex.h
gcc -c main.c -lm
complex.o: complex.c complex.h
gcc -c complex.c -lm
clean:
rm*.o complex
ls
main.o
main.o: complex.h
gcc -c main.c
complex.o
complex.o: complex.h
gcc -c complex.c
Error
mason% make
gcc -o complex main.o complex.o
ld: fatal: file main.o: unknown file type
ld: fatal: file processing errors. No output written to complex
collect2: error: ld returned 1 exit status
*** Error code 1
make: Fatal error: Command failed for target `complex'
It looks like you have put Makefile fragments inside main.o and complex.o. These should be generated by the compiler, not by you.
Delete these files, and make again.
Additionally, your make clean rule is missing a space.
clean:
rm *.o complex
ls
One more thing. No need for -lm in the compile lines.
main.o: main.c complex.h
gcc -c main.c
complex.o: complex.c complex.h
gcc -c complex.c
You should add -lm at the linking phase.
complex: main.o complex.o
gcc -o complex main.o complex.o -lm
The "Makefile" defines and controls the build dependencies.
For example, you can't build the main executable binary without first building the binary object/module files that go with it. In this case, those are main.o and complex.o.
Generally any object file you need also needs a rule (though some rules can use "wildcards" to build more).
This is all rather academic. Best to take errors at their word and try to disprove them (this one basically says that main.o exists and is incorrect). In this case the hypothesis that main.o exists is supported by the fact that it didn't compile when you ran the make command.
Until you learn more you could invoke "make" using "targets". Like: make clean and make complex. It might help bring clarity.
A lot of makefiles put an "all" target to sort of reset the build. That then depends on "clean" and the executable and library targets. Like:
all: clean complex
So then you "make all" to clean and build.
A good tutorial is here. Mrbook Makefile Tutorial

How do I change my makefile to avoid the undefined reference to a function in the maths library?

I'm trying to install PintOS on my local Ubuntu 14.04 machine. When I try to run make to compile the utilities. I get the following error.
ankitkal#ankitkal-Inspiron-5521:~/os/pintos/src/utils$ ls
backtrace Makefile pintos pintos.~1.55.~ pintos-mkdisk setitimer-helper.o squish-unix.c
CVS Makefile~ pintos~ pintos-gdb setitimer-helper.c squish-pty.c
ankitkal#ankitkal-Inspiron-5521:~/os/pintos/src/utils$ make
gcc -lm setitimer-helper.o -o setitimer-helper
setitimer-helper.o: In function `main':
setitimer-helper.c:(.text+0xbe): undefined reference to `floor'
collect2: error: ld returned 1 exit status
make: *** [setitimer-helper] Error 1
ankitkal#ankitkal-Inspiron-5521:~/os/pintos/src/utils$
The maths library (for the <math.h> header which is used in setitimer-helper.c) is not getting linked properly. When I look into the Makefile, this is the output.
ankitkal#ankitkal-Inspiron-5521:~/os/pintos/src/utils$ cat Makefile
all: setitimer-helper squish-pty squish-unix
CC = gcc
CFLAGS = -Wall -W
LDFLAGS = -lm
setitimer-helper: setitimer-helper.o
squish-pty: squish-pty.o
squish-unix: squish-unix.o
clean:
rm -f *.o setitimer-helper squish-pty squish-unix
Please tell me how to fix it. I'm using gcc-4.8.6 by the way.
gcc -lm setitimer-helper.o -o setitimer-helper
The problem is in the order of your arguments to GCC. Try this:
gcc -o setitimer-helper setitimer-helper.o -lm
This is because of the way that ld resolves undefined symbols when linking. Basically, the way you had it before, ld first sees -lm and says "I have no reason to include this library". It then includes your setitimer-helper.o which has an unresolved reference to floor. After that, there are no more libraries to consider, and floor remains unresolved.
If -lm comes afterward, it is able to resolve the reference to floor.

Resources