1

I am running Ubuntu 18.0.4 virtual machine using Vagrant and Virtualbox. I am writing a C program to manage virtual memory on said machine, which consists of many C and header files. Every time I run make while in my virtual machine, I get this error:

make[1]: Entering directory '/vagrant'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In 
function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:45: recipe for target 'vm-sim' failed
make[1]: *** [vm-sim] Error 1
make[1]: Leaving directory '/vagrant'
Makefile:23: recipe for target 'all' failed
make: *** [all] Error 2

Here is my Makefile:

TARGET = vm-sim
CC     = gcc
CFLAGS = -Wall -Wextra -Wsign-conversion -Wpointer-arith -Wcast-qual - 
Wwrite-strings -Wshadow -Wmissing-prototypes -Wpedantic -Wwrite-strings -g - 
std=gnu99 -lm

LFLAGS =

SRCDIR = *-src
INCDIR = $(SRCDIR)
BINDIR = .

SUBMIT_FILES  = $(SRC) $(INC) Makefile
SUBMISSION_NAME = project3-vm

SRC := $(wildcard $(SRCDIR)/*.c)
INC := $(wildcard $(INCDIR)/*.h)

INCFLAGS := $(patsubst %/,-I%,$(dir $(wildcard $(INCDIR)/.)))

.PHONY: all
all:
@$(MAKE) release && \
echo "$$(tput setaf 3)$$(tput bold)Note:$$(tput sgr0) this project compiled 
with release flags by default. To compile for debugging, please use $$(tput 
setaf 6)$$(tput bold)make debug$$(tput sgr0)."

.PHONY: debug
debug: CFLAGS += -ggdb -g3 -DDEBUG
debug: $(BINDIR)/$(TARGET)

.PHONY: release
release: CFLAGS += -mtune=native -O2
release: $(BINDIR)/$(TARGET)

.PHONY: clean
clean:
@rm -f $(BINDIR)/$(TARGET)
@rm -rf $(BINDIR)/$(TARGET).dSYM

.PHONY: submit
submit:
@(tar zcfh $(SUBMISSION_NAME).tar.gz $(SUBMIT_FILES) && \
echo "Created submission archive $$(tput 
bold)$(SUBMISSION_NAME).tar.gz$$(tput sgr0).")

$(BINDIR)/$(TARGET): $(SRC) $(INC)
@mkdir -p $(BINDIR)
@$(CC) $(CFLAGS) $(INCFLAGS) $(SRC) -o $@ $(LFLAGS)

I only have one main() function defined, but previously defined a different one in another file; I think this may be the issue but don't know how to fix it.

Matthew M
  • 21
  • 5
  • 2
    Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – SergeyA Mar 28 '19 at 19:03
  • 3
    You do build with the source file containing the `main` function? If you rebuild from scratch, do you see that source file being built into an object file? Is that object file linked with the rest for the executable program? You need to check the *full* output of `make` after e.g. `make clean`. – Some programmer dude Mar 28 '19 at 19:06
  • 1
    It is clearly not an issue of multiple definitions of main(), but rather _no_ definition of `main()`. The full _rebuild all_ (make clean/make) log will show you what is being compiled and linked - wherever main is defined - that is not in it. – Clifford Mar 28 '19 at 19:32
  • @Someprogrammerdude I'm afraid I'm not sure what you mean. How do I specify a source file for make? Or do you mean I should be running something like `gcc filename.c -o filename`? – Matthew M Mar 28 '19 at 19:35
  • 1
    Run `make clean`. Then run `make release` (or `make debug`). The `make` program will show you the exact commands that run to build your program. Is the source file containing your `main` function listed as being built? You *do* have a source file with a `main` function in it? – Some programmer dude Mar 28 '19 at 19:44
  • @Someprogrammerdude I do have a source file with a main function in it. However, after running `make clean`, both `make release` and `make debug` give me the same error I listed above. – Matthew M Mar 28 '19 at 20:09
  • is the source file that contains the `main()` function in the directory with the other source files? Does its' name follow the pattern: `*-src.c`? – user3629249 Mar 28 '19 at 20:18
  • the posted makefile does not seem to be following the rules about how recipe lines are added after a 'target' I.E.. each recipe line, after the target line, must start with a 'tab' char. Not start with a repeat of the 'target' – user3629249 Mar 28 '19 at 20:22
  • the macro: `TARGET` is not defined in the posted make file – user3629249 Mar 28 '19 at 20:26
  • @user3629249 The source file is in the same directory, yes, and it is named pagesim.c – Matthew M Mar 28 '19 at 20:26
  • well, the posted make file is expecting the file names to follow the pattern: `*-src.c` so `pagesim.c` does not follow that pattern, so will never be included in the `make` operations – user3629249 Mar 28 '19 at 20:28
  • @user3629249 I accidentally deleted the first line of the Makefile when copying it over, I have edited to fix it in the post – Matthew M Mar 28 '19 at 20:28
  • not a good idea to use '-' (dash) in executable names. Suggest using: `_' (underscore) – user3629249 Mar 28 '19 at 20:30
  • Is `pagesim.c` included in the output when building? – Some programmer dude Mar 29 '19 at 05:58

1 Answers1

0

the following makefile:

  1. is not for your specific directory layout
  2. shows a good (but not great) way to write the makefile
  3. shows one method for creating dependency files (however, gcc can be used directly to produce those files
  4. is written for a linux OS
  5. this is a generic make file, where the when the make is invoked, needs the parameter: -D name=executablename

and now, the makefile:

SHELL = /bin/sh


BINDIR  :=  /home/user/bin


.PHONY: all
all : $(BINDIR)/$(name) 



SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)




MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      := mv

LDFLAGS :=  -L/usr/local/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -Wextra -pedantic -Wconversion -std=gnu11


LIBS    :=   -lssl -ldl -lrt -lz -lc -lm



#
# link the .o files into the executable 
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ)  
    #
    # ======= $(name) Link Start =========
    $(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
    # ======= $(name) Link Done ==========
    #



# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
    #
    # ======= $(name) Copy Start =========
    sudo $(CP) $(name) $(BINDIR)/.
    # ======= $(name) Copy Done ==========
    #



#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c 
    # 
    # ========= START $< TO $@ =========
    $(CC)  $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



# 
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
clean: 
    # ========== CLEANING UP ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    # ========== DONE ==========



# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
user3629249
  • 16,402
  • 1
  • 16
  • 17