Trying to compile this code in a.s:
section .bss
global _start
global TestVar
TestVar: RESB 4
section .text
extern main
_start:
and this code in b.c:
extern int TestVar;
void test2(int x, int y)
{
int z = TestVar;
x = z + y;
y = 1;
}
int main(int argc, char **argv) {
return 0;
}
with this makefile:
all: test
test: a.o b.o
ld -melf_i386 a.o b.o -o test
a.o: a.s
nasm -f elf a.s -o a.o
b.o: b.c
gcc -m32 -Wall -g b.c -o b.o
.PHONY: clean
clean:
rm -f *.o test
running the makefile produces:
m#m-All-Series:~/testFolder$ make
nasm -f elf a.s -o a.o
gcc -m32 -Wall -g b.c -o b.o
/tmp/ccjymll2.o: In function `test2':
/home/m/testFolder/b.c:5: undefined reference to `TestVar'
collect2: error: ld returned 1 exit status
makefile:9: recipe for target 'b.o' failed
make: *** [b.o] Error 1
What am I doing wrong?
also, main is there just because if it isn't - the compiler says there is an undefined reference to main in _start in crt1.o, main will never be called, only test2, I don't know if that matters so I included that info as well.
You must use the compiler's -c option if you want to compile a C source into an object file. Without it, gcc tries to go on linking, which is not what you want. E.g.
b.o: b.c
gcc -c -m32 -Wall -g b.c
should get you a bit further.
Related
I am trying to compile two c files into one executable. In the directory I have only three files; Makefile, main.c and myfunction.c.
Makefile:
CC = gcc
CFLAGS = -Wall -g -O0
LIBS = -lm
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
MAIN = main
all: $(MAIN)
#echo Program has been compiled
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LIBS)
clean:
$(RM) *.o *~ $(MAIN)
main.c:
#include <stdio.h>
void myfunc();
int main (int argc, char *argv[]) {
myfunc();
return 0;
}
myfunction.c:
#include <stdio.h>
void myfunc() { printf("hello world"); }
output after make:
gcc -Wall -g -O0 -c -o main.o main.c
gcc -Wall -g -O0 -c -o myfunction.o myfunction.c
gcc -Wall -g -O0 -o main main.o myfunction.o -lm
Undefined symbols for architecture x86_64:
"_myfunc", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [main] Error 1
I had something nearly identical working in the past. I have since clean installed MacOS and updated to Big Sur. Is this the issue or have I overlooked something?
I fixed the issue. I’m not sure what part fixed it, but installed Homebrew and used it to install gcc-10. I also deleted the project and started over.
myfunc would define like file header
myfunc.h
void myfunc()
Declare in another file
myfunc.c
void myfunc() { printf("hello world"); }
Follow the following tutorial
https://developer.gnome.org/anjuta-build-tutorial/stable/build-make.html.en
We've got the exercise to create a makefile, which should "create a project bbfoo. bbfoo is linked from barbaz and foo. barbaz is linked from bar and baz. Use the compiler cc (which is gcc on my system) and the linker ld."
I created three simple c files:
bar.c:
int one() {
return 1;
}
baz.c:
int two() {
return 2;
}
foo.c
#include <stdio.h>
int main() {
printf("bar: %d\n", one());
printf("baz: %d\n", two());
return 0;
}
and the following makefile:
bar: bar.c
cc -c -g -o bar.o bar.c
baz: baz.c
cc -c -g -o baz.o baz.c
barbaz: bar baz
ld -shared -o barbaz.o bar.o baz.o
foo: foo.c
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
bbfoo: barbaz foo
ld -lc --entry=main -o bbfoo.out barbaz.o foo.o
$ make bbfoo
works without an error and the corresponding files are created. But when I try to run the project with
$ ./bbfoo.out
it displays "File or folder not found".
It works flawless when I use gcc:
$ gcc -o bbfoo.out bar.c baz.c foo.c
$ ./bbfoo.out
bar: 1
baz: 2
What's my mistake? Is it even possible to link a project like this (in two steps)?
Your makefile uses ld to link, but your gcc example uses the compiler driver to link. You should do the same:
bbfoo: barbaz foo
gcc -o bbfoo.out barbaz.o foo.o
The compiler driver may (and in your case clearly does) include a bunch of system-specific stuff that makes your program actually work. Trying to run the linker directly is usually not recommended.
You can use GCC's -v flag if you want to see what the link line it's really using is and copy the flags from that into your makefile if you want, too. But then you're at risk of not picking up important changes in the future.
If you use make you should stick with its basic principle which we can summarize as:
FILE-to-create: files-used-to-create-FILE
shell-commands-that-create-FILE
It is extremely important because make compares last modification times of files to decide what is out of date and what is up to date. It is not a formality and it does change the functionality. So, in your case, you should have:
bar.o: bar.c
cc -c -g -o bar.o bar.c
baz.o: baz.c
cc -c -g -o baz.o baz.c
foo.o: foo.c
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
barbaz.so: bar.o baz.o
ld -shared -o barbaz.so bar.o baz.o
bbfoo: barbaz.so foo.o
ld -lc --entry=main -o bbfoo barbaz.so foo.o
Note that make has some nice features that can help factorizing this kind of simple set of rules. Like, for instance automatic variables ($#, $^...), implicit rules (e.g. for building the *.o object files from *.c source files), implicit variables used by the implicit rules (CFLAGS, LD...), target-specific variable values (look at the CFLAGS declaration for foo.o) and many more. Example:
CFLAGS := -g
foo.o: CFLAGS += -Wno-implicit-function-declaration
barbaz.so: bar.o baz.o
$(LD) -shared -o $# $^
bbfoo: barbaz.so foo.o
$(LD) -lc --entry=main -o $# $^
Yes, no rules at all for the object files, make knows already how to build them.
the posted code contains a lot of shortcomings.
Suggest:
bar.h
#ifndef BAR_H
#define BAR_H
int one( void );
#endif
bar.c:
#include "bar.h"
int one() {
return 1;
}
baz.h
#ifndef BAZ_H
#define BAZ_H
int one( void );
#endif
baz.c:
#include "baz.h"
int two() {
return 2;
}
foo.c
#include <stdio.h>
#include "bar.h"
#include "baz.h"
int main( void ) {
printf("bar: %d\n", one());
printf("baz: %d\n", two());
return 0;
}
makefile.mak
.PHONY all
all: bbfoo.out
bar: bar.c bar.h
cc -c -g -o bar.o bar.c -Ibar.h
baz: baz.c baz.h
cc -c -g -o baz.o baz.c -Ibaz.h
libbarbaz.so: baz.o bar.o
ld -shared -o libbarbaz.so bar.o baz.o
foo: foo.c baz.h bar.h
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c -Ibar.h -Ibaz.h
bbfoo.out: foo.o libbarbaz.so
ld -lc --entry=main -o bbfoo.out foo.o -lbarbaz
Using the short cut variables found in make would greatly shorten this makefile but would make it much more cryptic
Header lab3p2.h
#ifndef LAB3P2_H
#define LAB3P2_H
long power(int integer1, int integer2);
#endif
Power Function: lab3p2f1.c
#include "lab3p2.h"
#include <stdio.h>
long power(int integer1, int integer2){
int i;
long ret =(long) integer1;
if(integer2 ==0)
{
ret = 1;
}else{
for( i =1 ; i < integer2; i++)
{
ret = ret * integer1;
}
}
return ret;
}
Main: lab3p2.c
#include <stdio.h>
#include "lab3p2.h"
/*Takes in integers from the command line and returns the power function result*/
int main(int argc, char **argv){
int a = atoi( *(argv+1));
int b = atoi( *(argv+2));
int c =atoi( *(argv+3));
long functionResult;
functionResult = power(b,c);
printf("The result of the power function is %ld \n", functionResult);
}
MakeFile: makefile
all: lab3p2
mkprog: lab3p2.o lab3p2f1.o
gcc lab3p2.o lab3p2f1.o -o lab3p2
lab3p2.o: lab3p2.c
gcc -ansi -pedantic -c lab3p2.c
lab3p2f1.o: lab3p2f1.c
gcc -ansi -pedantic -c lab3p2f1.c
clean:
rm -rf *.o lab3p2
Why can the main not access the function?
Is something wrong with how I am compiling?
Any help is greatly appreciated.
You're missing the rule for target lab3p2; i.e. mkprog should be lab3p2:
all: lab3p2
lab3p2: lab3p2.o lab3p2f1.o
gcc lab3p2.o lab3p2f1.o -o lab3p2
lab3p2.o: lab3p2.c
gcc -ansi -pedantic -c lab3p2.c
lab3p2f1.o: lab3p2f1.c
gcc -ansi -pedantic -c lab3p2f1.c
clean:
rm -rf *.o lab3p2
With your current Makefile, when you run make without arguments, you will get the following output:
% make
gcc -ansi -pedantic -c lab3p2.c
cc lab3p2.o -o lab3p2
lab3p2.o: In function `main':
lab3p2.c:(.text+0x6b): undefined reference to `power'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'lab3p2' failed
make: *** [lab3p2] Error 1
What happens is that make tries to satisfy the first target (i.e. all); this then requires lab3p2. As make cannot find an explicit rule to build lab3p2 it then tries an implicit one - it knows that one can build foo by linking foo.o into a program; thus it runs the command
cc lab3p2.o -o lab3p2
However, this command doesn't link in the lab3p2f1.o where the definition for power resides.
These implicit rules can be quite handy with simple projects; for example for your project, the Makefile for GNU make could be simply written as
CC = gcc
CFLAGS = -ansi -pedantic
all: lab3p2
lab3p2: lab3p2.o lab3p2f1.o
clean:
rm -rf *.o lab3p2
and make would automatically figure out how to build the .o from corresponding .c and that it should use the compiler from the CC variable, and pass arguments from the CFLAGS.
Makefile:
all: a.out
a.out: b.o a.o
gcc -o b.o a.o
a.o: a.c
gcc -c a.c
b.o: b.c
gcc -c b.c
.PHONY:clean
clean:
rm *.o a.out
with make, give information:
error: undefined reference to 'main'
collect2: ld return 1
make: * [a.out] error 1
But when put source file a.c and b.c into Eclipse CDT, it compiles well.
Please explain what is wrong with my makefile?
PS:
a.c:
int global_1 = 100;
b.c:
extern int global_1;
int main()
{
int global_2 = global_1 * 2;
return 0;
}
This rule doesn't specify the correct result file:
a.out: b.o a.o
gcc -o b.o a.o
It should be
a.out: b.o a.o
gcc -o "$#" b.o a.o
That's what you get for violating one of Paul's Rules of Makefiles. BTW, it's not the makefile that "gives the error", it's the compilation, specifically the linker.
This:
a.out: b.o a.o
gcc -o b.o a.o
\----/
|
|
this says "name
the output b.o"
is overwriting the b.o object file with the output file. I'm pretty sure make is clever enough to figure the required command out without any input, so try deleting the second line.
I have created two files:
tunables.h
#ifndef TUNABLES_H
#define TUNABLES_H
void tunables_load_conservative();
void tunables_load_aggressive();
extern int timer_x;
#endif /*TUNABLES_H */
and tunables.c
#include "tunables.h"
int timer_x;
void tunables_load_conservative(){
timer_x = 3;
}
void tunables_load_aggressive(){
timer_x = 1;
}
All the other files of my project includes "tunables.h". When I load the project both A.c and B.c calls tunables_load_conservative but if, after a while, I call in file A.c tunables_load_aggressive() in file B.c the timer_x remains 3. Why?
This is my Makefile:
INCLUDE=`pwd`/include
GCCFLAGS= -ansi -O3 -pedantic -Wall -Wunused -I${INCLUDE} -DDEBUG
GCCOTHERFLAGS= -ggdb -pg
all: A B
A: A.o tunables.o
gcc -o A ${GCCFLAGS} ${GCCOTHERFLAGS} tunables.o
B: B.o tunables.o
gcc -o LBfixed ${GCCFLAGS} ${GCCOTHERFLAGS} tunables.o
A.o: A.c
gcc -c ${GCCFLAGS} ${GCCOTHERFLAGS} A.c
B.o: B.c
gcc -c ${GCCFLAGS} ${GCCOTHERFLAGS} B.c
tunables.o: tunables.c
gcc -c ${GCCFLAGS} ${GCCOTHERFLAGS} tunables.c
clean:
rm -rf *.o A B
It looks like you've got two separate processes, A and B. The extern declaration does not set up shared memory across processes, but instead allows different compilation units within the same process to access the same variable.
To share a variable across processes, you will need to use system-dependent IPC methods.