How to fix linker error when compiling XV6? - c

I have three files in my XV6: testmain.c, foo.h, and foo.c :
foo.h :
extern void myfunction(void)
foo.c:
#include "foo.h"
void myfunction(void){
printf(1, "HelloWorld"); }
testmain.c:
#include "foo.h"
int main(void){
myfunction();
return 0 ; }
I am getting undefined reference error for myfunction() in test_main . I know I need to change something in Makefile for XV6, but I don't know what. that's what I have changed in XV6 Makefile:
UPROGS=\
_cat\
_echo\
_forktest\
_grep\
_init\
_kill\
_ln\
_ls\
_mkdir\
_rm\
_sh\
_stressfs\
_usertests\
_wc\
_zombie\
_foo\
_testmain\

You need several changes in Makefile:
Indicate that you want to create _testmain program,
Tell what _testmain dependencies are (if apply).
add _testmain in programs list:
UPROGS=\
_testmain\
_cat\
_crash\
_echo\
_factor\
....
_testmain dependencies:
Since your _testmain program depends on two files, you must create a special rule telling that to builder (I make this rule from _%: %.o $(ULIB) rule):
_testmain: testmain.o foo.o $(ULIB)
$(LD) $(LDFLAGS) -N -e main -Ttext 0x1000 -o $# $^
$(OBJDUMP) -S $# > $*.asm
$(OBJDUMP) -t $# | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym

Related

Undefined reference to function that is already defined in my header file

I have three files, posl.h, state.c and main.c. What I plan on doing is adding functions that are used throughout the project in posl.h, and then I call it to test the function with main.c, and then make the function in state.c. The problem I am having is that I keep getting an error of undefined reference to init_poslState() even though I have it defined in posl.h
main.c
#include <posl.h>
int main(int argc, char * argv[]) {
pState poslState = init_poslState();
return 0;
}
posl.h
#ifndef POSL_LANGUAGE_H
#define POSL_LANGUAGE_H
#define POSL_MAJOR_VERSION 1
#define POSL_MINOR_VERSION 0
#define POSL_RELEASE_VERSION 0
// State
typedef struct POSL_STATE {
// ...
} pState;
pState init_poslState();
void free_poslState(pState poslState);
#endif
state.c
#include "state.h"
#include <posl.h>
pState init_poslState() {
pState newState;
return newState;
}
Makefile
CFLAGS=-g -Wall -Wextra -I./include
CC=gcc $(CFLAGS)
CORE_O_FILES=./src/Core/lexer.o ./src/Core/parser.o ./src/Core/state.o
CLI_O_FILES=
O_FILES=$(CORE_O_FILES)
# Making CLI Tool
posl: $(CLI_O_FILES) libposl.a ./src/CLI/main.c
$(CC) -o posl -L./ -lposl ./src/CLI/main.c $(CLI_O_FILES)
# Making Library
libposl.a: $(O_FILES) ./include/posl.h
ar rcs libposl.a $^
# Core Files
./src/Core/lexer.o: ./src/Core/lexer.c ./src/Core/lexer.h
$(CC) -o $# -c ./src/Core/lexer.c
./src/Core/parser.o: ./src/Core/parser.c ./src/Core/parser.h
$(CC) -o $# -c ./src/Core/parser.c
./src/Core/state.o: ./src/Core/state.c ./src/Core/state.h
$(CC) -o $# -c ./src/Core/state.c
# PHONY List
.PHONY: all
all:
make update-libs
make libposl.a
make posl
make pcc
# Post-Compile Clean
.PHONY: pcc
pcc:
rm -rf ./src/Core/*.o
rm -rf ./src/CLI/*.o
.PHONY: clean
clean:
make pcc
rm -rf ./libposl.a ./posl*
The order of compiler and (especially) linker options is significant. With this command ...
$(CC) -o posl -L./ -lposl ./src/CLI/main.c $(CLI_O_FILES)
... the linker will not attempt to resolve any function references from main.c against functions in libposl.a. It will look only to objects and libraries appearing after main.c on the command line.
Therefore, rewrite that recipe to
$(CC) -o posl -L. ./src/CLI/main.c $(CLI_O_FILES) -lposl
Welp, #user17732522 answered my question. I had the -l flag messed up, and it wasn't after my source files. ~Thank you guys!~

multiple definition of `function' error occurring on the same line as "first defined here"

error log
paging.c: In function ‘setup_paging_structures’:
paging.c:7: warning: implicit declaration of function ‘printf’
rm -f bootimg
gcc -nostdlib -static boot.o paging.o x86_desc.o i8259.o kernel.o lib.o paging.o tests.o -Ttext=0x400000 -o bootimg
paging.o: In function `setup_paging_structures':
/workdirmain/work/mp3_group_31/student-distrib/paging.c:4: multiple definition of `setup_paging_structures'
paging.o:/workdirmain/work/mp3_group_31/student-distrib/paging.c:4: first defined here
paging.o: In function `initialize_paging':
/workdirmain/work/mp3_group_31/student-distrib/paging.c:13: multiple definition of `initialize_paging'
paging.o:/workdirmain/work/mp3_group_31/student-distrib/paging.c:13: first defined here
collect2: ld returned 1 exit status
make: *** [bootimg] Error 1
Here's what my paging.h file looks like:
#ifndef _PAGING_H
#define _PAGING_H
#include "types.h"
#define TOTAL_ENTRIES 1024
extern void setup_paging_structures();
extern void initialize_paging();
#endif
Paging.c below:
#include "paging.h" //include header files
void setup_paging_structures(){
int i;
for (i = 0; i < TOTAL_ENTRIES; i++){
printf("weird");
}
return;
}
void initialize_paging(){
setup_paging_structures();
return;
}
Note, I have not called the functions yet.
The command I'm using is "sudo make" (Makefile was given to me. I'm pretty sure I'm not supposed to modify it):
# Makefile for OS project
# To build, first `make dep`, them `make`. Everything should be automatic.
# Will compile all *.c and *.S files in the current directory.
# Flags to use when compiling, preprocessing, assembling, and linking
CFLAGS+=-Wall -fno-builtin -fno-stack-protector -nostdlib
ASFLAGS+=
LDFLAGS+=-nostdlib -static
CC=gcc
#If you have any .h files in another directory, add -I<dir> to this line
CPPFLAGS+=-nostdinc -g
# This generates the list of source files
SRC=$(wildcard *.S) $(wildcard *.c) $(wildcard */*.S) $(wildcard */*.c)
# This generates the list of .o files. The order matters, boot.o must be first
OBJS=boot.o
OBJS+=$(filter-out boot.o,$(patsubst %.S,%.o,$(filter %.S,$(SRC))))
OBJS+=$(patsubst %.c,%.o,$(filter %.c,$(SRC)))
bootimg: Makefile $(OBJS)
rm -f bootimg
$(CC) $(LDFLAGS) $(OBJS) -Ttext=0x400000 -o bootimg
sudo ./debug.sh
dep: Makefile.dep
Makefile.dep: $(SRC)
$(CC) -MM $(CPPFLAGS) $(SRC) > $#
.PHONY: clean
clean:
rm -f *.o */*.o Makefile.dep
ifneq ($(MAKECMDGOALS),dep)
ifneq ($(MAKECMDGOALS),clean)
include Makefile.dep
endif
endif
edit: I added updates to my post including the actual directories, the entire error log, and the contents of the Makefile I am using. This is also for a class that I'm currently taking, hence some of the things that were automatically given to me.

Trouble Writing My First Makefile

So here is my Makefile:
# My First Makefile
HEADERS = stdio.h
all: main.o input.o output.o
cc -o all main.o input.o output.o
main.o: main.c $(HEADERS)
cc -c main.c -o main.o
input.o: input.c $(HEADERS)
cc -c input.c -o input.o
output.o: output.c $(HEADERS)
cc -c output.c -o output.o
clean:
-rm -f *.o
-rm -f all
And below is input.c:
#ifndef __STDIO_H__
#define __STDIO_H__
#include <stdio.h>
void getChar()
{
getchar();
}
#endif
Below is output.c:
#ifndef __STDIO_H__
#define __STDIO_H__
#include <stdio.h>
void putChar(char c)
{
putchar(c);
}
#endif
Below is main.c:
#ifndef __STDIO_H__
#define __STDIO_H__
#include <stdio.h>
int main()
{
char c;
while ((c = etChar()) != '\n')
{
putChar(c);
}
}
#endif
Yet whenever I press "make" command in Terminal,
I get:
make: *** No rule to make target `stdio.h', needed by `main.o'. Stop.
cc refers to clang
What is it that I am doing wrong here?
I was trying to get used to $(ARGS) by using $(HEADERS)
but it seems that the clang compiler does not accept this.
Do you think I should use gcc instead?
It is unnecessary to write stdio.h in your Makefile. GCC will automatically search it in DEFAULT PATH (/usr/include, ....). Write header files as targes in Makefile only if you use your own header files.
# Makefile
# define CC
CC := gcc
# define final targets
TARGETS := main
# just trigger $(TARGETS)
all: $(TARGETS)
# build main from main.o, input.o, output.o
main: main.o input.o output.o
$(CC) -o $# $^
# build main.o/input.o/output.c from main.c/input.c/output.c
%.o: %.c
$(CC) -c -o $# $<
# trigger $(TARGETS), then run ./main
run: $(TARGETS)
./main
clean:
-rm $(TARGETS)
-rm *.o
# define targets which are not bound to file
.PHONY: all clean run
In your case:
"make" will look for stdio.h in the current directory, and is complaining that the header is not found.
Just to fix this, you should mention the full path where stdio.h is located, for example:
HEADERS = /usr/include/stdio.h
Ideally, if you want to check for the presence of standard headers like stdio.h, you should use tools like automake and autoconf, which generate the Makefile automatically. Here's a link which points to the autoconf documentation:
https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html

Forcing Orders in Makefile Dependencies

I need some help writing a GNU makefile. I have a C program "main.c", which is dependent on the value of "CONSTANT" defined in the file "constants.h".
"main.c"
#include <stdio.h>
#include "constants.h"
void work(void)
{
int array[CONSTANT];
for (int i = 0; i < CONSTANT; i++) {
printf("%d\n", i);
}
}
int main(int argc, char const* argv[])
{
printf("constant=%d\n", CONSTANT);
work();
return 0;
}
"constant.h"
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define CONSTANT 4
#endif
What I'm trying to do here is to compile the program with different values for "CONSTANT". For example, "out1" is compiled with "CONSTANT=1" and with "make all", I should be able to produce all the variants ("out1", "out2" and "out4").
The problem is that "a.o" required by "main.c" also depends on the value of "CONSTANT". So "a.o" must be compiled after "sed%". However, as far as I understand, there is no way in "make" to force orders in dependencies (I guess this is the whole point of using makefiles).
What is the recommended way to address this situation?
"Makefile"
CC= gcc
CFLAGS = -std=c99 -Wall
CONSTANTS = 1 2 4
targets = $(addprefix out, $(CONSTANTS))
seds = $(addprefix sed, $(CONSTANTS))
.PHONY: $(seds)
$(seds): sed%:
sed -i 's/define CONSTANT [0-9]*/define CONSTANT $*/g' constants.h
$(targets): out%: main.c sed% a.o
$(CC) $(CFLAGS) $< a.o -o $#
a.o: a.c constant.h
$(CC) $(CFLAGS) $< a.o -o $#
.PHONY: all
all : $(targets)
Note that I'm aware that I can rewrite "main.c" so that it takes a parameter from the comman line. In practice, many other files other than "main.c" depend on "CONSTANT", so I want to avoid rewriting all these files. I'm also aware that I can do something like "gcc -DCONSTANT=n main.c", but every file dependent on "CONSTANT" must be recompiled as well.
Related Questions
How to specify Makefile target building order without put any physical dependencies?
Force order of dependencies in a Makefile
I'm ... aware that I can do something like "gcc -DCONSTANT=n main.c",
but every file dependent on "CONSTANT" must be recompiled as well.
This needn't be a hindrance if you have your makefile generate
the correct -DCONSTANT=n and distinct object file in every compilation recipe.
Here's an illustration:
constants.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
#ifndef CONSTANT
#define CONSTANT 4
#endif
#endif
foo.c
#include "constants.h"
int foo = CONSTANT;
main.c
#include <stdio.h>
#include "constants.h"
extern int foo;
int main()
{
printf("%d\n",CONSTANT + foo);
return 0;
}
Makefile
CC := gcc
CFLAGS := -std=c99 -Wall
CONSTANTS = 1 2 4
TARGETS = $(addprefix out, $(CONSTANTS))
SRCS := main.c foo.c
define compile =
$(basename $(1))$(2).o: $(1) constants.h
$$(CC) -c -DCONSTANT=$(2) $$(CFLAGS) $$< -o $$#
endef
.PHONY: all clean
all : $(TARGETS)
$(foreach src,$(SRCS),\
$(foreach const,$(CONSTANTS),$(eval $(call compile,$(src),$(const)))))
out%: main%.o foo%.o
$(CC) $^ -o $#
clean:
rm -f $(TARGETS) *.o
This runs like:
$ make
gcc -c -DCONSTANT=1 -std=c99 -Wall main.c -o main1.o
gcc -c -DCONSTANT=1 -std=c99 -Wall foo.c -o foo1.o
gcc main1.o foo1.o -o out1
gcc -c -DCONSTANT=2 -std=c99 -Wall main.c -o main2.o
gcc -c -DCONSTANT=2 -std=c99 -Wall foo.c -o foo2.o
gcc main2.o foo2.o -o out2
gcc -c -DCONSTANT=4 -std=c99 -Wall main.c -o main4.o
gcc -c -DCONSTANT=4 -std=c99 -Wall foo.c -o foo4.o
gcc main4.o foo4.o -o out4
And the resulting programs run like:
$ for i in 1 2 4; do ./out$i; done
2
4
8

`multiple definition of` lots of variables error - is my make file incorrect?

I am getting an error when I compile multiple definition of lots of variables. For example:
/tmp/ccwHwJ7t.o:(.data+0x0): multiple definition of `serial_number'
/tmp/ccmT1XNI.o:(.data+0x0): first defined here
All the variables are located in ftdi.h, which is included by main.c. Is there something wrong with my make file that is causing this to be included twice? or am I looking in the wrong directio.
SSHELL = /bin/sh
CC = gcc
APP = npi_usb_ftdi
INC = include
INCDIRS +=-I${INC}
CFLAGS= ${INCDIRS} -Wall -Wextra
LIBS = libftd2xx.a -ldl -lpthread -lrt
all: ${APP}
${APP}: src/main.c src/ftdi.c src/vt100.c src/monitor.c
${CC} ${CFLAGS} src/main.c src/ftdi.c src/vt100.c src/monitor.c -o ${APP} ${LIBS}
ftdi.o:
${CC} -c -o src/ftdi.o src/ftdi.c
vt100.o:
${CC} -c -o src/vt100.o src/vt100.c
monitor.o:
${CC} -c -o src/monitor.o src/monitor.c
clean:
rm -f src/*.o ; rm -f src/*~ ; rm -f *~ ; rm -f ${APP}
You probably include the .h file in other source files too. No problem, but only in one source file should the variables be declared and in the others just defined. I use:
// ftdi.h
#ifndef EXTERN
# define EXTERN extern
#endif
EXTERN int examplevar;
// main.c
#define EXTERN
#include "ftdi.h"
// ftdi.c
#include "ftdi.h"

Resources