Why does undefined reference disappear after adding a .cpp file with empty main function when building shared library - makefile

I have makefile that builds shared library libsimpletron.so:
#shell
MKDIR_P = mkdir -p
#compiler
CC = g++
#cpp flags
FLAGS = -std=c++1z
CPPFLAGS = -fPIC -Wall -Wextra
LDFLAGS = -shared
#directories
INC_DIR = ../inc
LIB_DIR = ../lib
BIN_DIR = ../bin
OBJ_DIR = ./obj
ALG_DIR = ./algebra
SOURCES = $(shell echo *.cpp)
HEADERS = $(shell echo $(INC_DIR)/*.h)
_OBJECTS = $(SOURCES:.cpp=.o)
OBJECTS = $(patsubst %,$(OBJ_DIR)/%,$(_OBJECTS))
ALGEBRA = $(LIB_DIR)/libalgebra.so
TARGET = $(LIB_DIR)/libsimpletron.so
.PHONY: directories
all : directories $(ALGEBRA) $(TARGET)
directories: $(OBJ_DIR) $(BIN_DIR) $(LIB_DIR)
$(OBJ_DIR):
$(MKDIR_P) $(OBJ_DIR)
$(BIN_DIR):
$(MKDIR_P) $(BIN_DIR)
$(LIB_DIR):
$(MKDIR_P) $(LIB_DIR)
$(ALGEBRA):
$(MAKE) -C $(ALG_DIR)
$(OBJ_DIR)/%.o: %.cpp $(HEADERS)
$(CC) -c $(FLAGS) $(CPPFLAGS) -o $# $<
$(TARGET) : $(OBJECTS)
$(CC) $(LDFLAGS) -o $# $^
.PHONY: clean
clean:
rm -f $(OBJ_DIR)/*.o
make command builds library successfully (I think) :
g++ -c -std=c++1z -fPIC -Wall -Wextra -o obj/builder.o builder.cpp
...similar lines for each .cpp file...
g++ -shared -o ../lib/libsimpletron.so obj/builder.o obj/gradient_trainer.o obj/layer.o obj/neuron.o obj/perceptron.o obj/simpletron.o obj/trainer.o
Then I am trying to use this library. I compile my test xor as follows:
#compiler
CC = g++
#cpp flags
FLAGS = -std=c++1z
PUGI = -l pugixml
#directories
LIB_DIR = /home/lrdprdx/Projects/SimplePerceptron/lib
SIMPLETRON = -lsimpletron
ALGEBRA = -lalgebra
XOR = xor
SOURCE = xor.cpp
#config file
CONFIG = config.xml
$(XOR) : $(SOURCE) $(CONFIG)
$(CC) $(FLAGS) -L$(LIB_DIR) $(SIMPLETRON) $(ALGEBRA) $(PUGI) -o $(XOR) $(SOURCE)
But when I try to compile this I get errors of undefined reference to .... OK, though I do not understand why those errors exist, I found that adding a .cpp file with an empty main function to the directory with other .cpp files fixes all the stuff:
//empty.cpp
int main()
{
return 0;
}
And after rebuild the shared library I make and execute xor successfully.
The question is: what is going on here?

I doubt that adding the extra file really fixed anything. Most likely some other side-effect helped.
Your problem is that your link line is incorrect. GCC, like most UNIX linkers, is a single-pass linker. That means it only walks all the libraries one time looking for unresolved symbols. And that means that the order of the arguments to the linker is critically important: you have to ensure that if item A references symbols in item B, that A comes before B on the link line.
In your example, you are putting all your libraries first, and your source files last. So, when make starts looking at your libraries it hasn't seen your sources yet, and there are no symbols it needs to link. By the time it compiles your sources, there are no libraries left to resolve symbols from.
Your link line should be arranged with sources and object files first, then libraries (in referencer ... referencee order):
$(CC) $(FLAGS) $(SOURCE) -L$(LIB_DIR) $(SIMPLETRON) $(ALGEBRA) $(PUGI) -o $(XOR)

Related

Can't use LAPACK in makefile

I have program (in fortran) where I'm using three custom modules, which make use of LAPACK. Until now I've compiled my program using the following shell script:
filestring="main"
gfortran -c mod_exp.f90 mod_genmat.f90 mod_print.f90 $filestring.f90
gfortran mod_exp.o mod_genmat.o mod_print.o $filestring.o -llapack -lblas
rm mod_exp.o mod_genmat.o mod_print.o $filestring.o exponentiate.mod genmat.mod printing.mod printing_subrtns.mod
mv a.out $filestring
Since I've been using more and more modules and different programs using them, I've decided to start using makefiles. Following a tutorial, I managed to write the following:
FC = gfortran
FFLAGS = -Wall -Wextra -llapack -lblas #-fopenmp
SOURCES = mod_print.f90 mod_genmat.f90 mod_exp.f90 main.f90
OBJ = ${SOURCES:.f90=.o} #substitute .f90 with .o
%.o : %.f90 #creation of all *.o files DEPENDS on *.f90
$(FC) $(FFLAGS) -c -O $< -o $#
main: $(OBJ)
$(FC) $(FFLAGS) -o $# $(OBJ)
clean:
#rm -f *.o *.mod main
However, when executing make, it says that the LAPACK functions are not recognized. One such mistake is the following:
/usr/bin/ld: mod_exp.o: in function `__exponentiate_MOD_diagun':
mod_exp.f90:(.text+0x37f): undefined reference to `zgees_'
...
collect2: error: ld returned 1 exit status
One possible mistake I've seen is that I need to specify the location of the libraries. However, it would seem strange since I didn't need to do it before; also, I don't know how to find it.
Please show the link command that make invoked, that caused the error to be generated.
I'm confident that if you cut and paste that exact command line to your shell prompt, you will get the same error you see when make runs it. So the problem is not make, but your link command.
The problem is that you have put the libraries before the objects in the link line. Libraries should come at the end, after the objects, else when the linker examines the libraries it doesn't know what symbols will need to be included (because no objects have been parsed yet to see what symbols are missing).
This is why LDLIBS is traditionally a separate variable:
FC = gfortran
FFLAGS = -Wall -Wextra #-fopenmp
LDLIBS = -llapack -lblas
SOURCES = mod_print.f90 mod_genmat.f90 mod_exp.f90 main.f90
OBJ = ${SOURCES:.f90=.o} #substitute .f90 with .o
%.o : %.f90 #creation of all *.o files DEPENDS on *.f90
$(FC) $(FFLAGS) -c -O $< -o $#
main: $(OBJ)
$(FC) $(FFLAGS) -o $# $(OBJ) $(LDLIBS)

make file for Gtk

I have a make file, which creates obj files for all source files and then the executable using those obj files (basically compiling each individual file and then linking all of them together).
CC = gcc
SRC_DIR = src
INC_DIR = inc
OBJ_DIR = obj
CFLAGS = -c -Wall -I$(INC_DIR)
EXE = project
SRCS = $(SRC_DIR)/main.c $(SRC_DIR)/file1.c # and so on...
OBJS = $(OBJ_DIR)/main.o $(OBJ_DIR)/file1.o # and so on...
main : clean build
build: $(OBJS)
$(CC) $(OBJS) -o $(EXE)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
I tried to do the same for gtk+3.0 but haven't been successful as the examples on the web always have been with respect to the example file and not the project as a whole (consisting multiple source files). one such eg:
$ cc `pkg-config --cflags --libs gtk+-3.0` hello.c -o hello
Make file for gtk+ is:
CC = gcc
SRC_DIR = .
INC_DIR = .
OBJ_DIR = Obj
CFLAGS = -Wall -g -o
PACKAGE = `pkg-config --cflags --libs gtk+-3.0`
LIBS = `pkg-config --libs gtk+-3.0`
EXE = Gui
SRCS = $(SRC_DIR)/main.c
OBJS = $(OBJ_DIR)/main.o
main : clean build
build: $(OBJS)
$(CC) $(OBJS) -o $(EXE)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(PACKAGE) $(CFLAGS) $< -o $#
But this doesn't work. It gives errors (undefined reference to 'gtk_init' and other gtk functions)
What modifications should i do?
It should be
LDLIBS = $(shell pkg-config --libs gtk+-3.0)
instead of LIB
Check with make -p your builtin rules.
Look also at this example. See $(LINK.o) variable, etc.
The CFLAGS must have -c or that must be included while compiling. Also, the pkg-config must be included during linking.
After the changes, the make file becomes:
build: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(EXE) $(LIBS)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) ***-c*** -I$(INC_DIR) $< -o $# $(PACKAGE)
The changes run successfully.

Fortran: makefile with multiple directories

I have a large fortran project like this:
project
|-\bin
|-\obj
|-\src
|--\fortran
|---\common
|---\prePro
I am trying to build a makefile like this one:
F90 = gfortran
FFLAGS = -O3
VPATH = modules:interfaces:subroutines
SRCOBJ = $(wildcard modules/*f90)
MODOBJ = $(SRCOBJ:.f90=.o)
your_executable: $(MODOBJ) main.o
$(F90) main.o -o your_executable
%.o:%.f90
$(F90) $(FFLAGS) -c $^ -o $#
that lies on the bin directory. For now I came up with this:
FC = gfortran
FFLAGS = -O3
VPATH = ../src/fortran/common:../src/fortran/prePro:
SRCOBJ = $(wildcard ../src/fortran/common/*.f90) $(wildcard ../src/fortran/prePro/*.f90)
MODOBJ = $(SRCOBJ:.f90=.o)
all: prePro
prePro: $(MODOBJ) prePro.o
$(FC) prePro.o -o prePro
%.o %.mod:%.f90
$(FC) $(FFLAGS) -c $^ -o $#
However this don't work because most of my files are modules and they depend on each other.
Adding the dependencies manually fix the issue, i.e.:
../src/fortran/common/common_routines.o: ../src/fortran/common/types.o ../src/fortran/common/global.o
../src/fortran/common/global.o: ../src/fortran/common/types.o
etc...
Is there any easier (shorter) way to fix the dependency issues?
Bonus question: How can I trow the objects and modules in a obj folder and link the program from there?

How to use lib file to make another lib in Makefile

I want to make a lib file which is using another my lib file. I've tried various combinations in makefile to do linking, but sometimes it asking that linking command ignored or not warning but crashes when I'm trying to use code from libs. My makefile looks like this:
SRC = a.cpp b.cpp c.cpp etc.
OBJ = $(SRC:.cpp=.o)
OUT = ./libHTTPServer.a
INCLUDES := -I/home/myuser/Development/boost_1_51_0 \
-I/home/myuser/Development/HTTPServers/Prot
CCFLAGS = -g
CCC = g++
LIBS = -L/home/myuser/Development/boost_1_51_0/buildedlibs/lib -lm
LDFLAGS = -g
.SUFFIXES: .cpp
.cpp.o:
$(CCC) $(INCLUDES) $(CCFLAGS) -c $< -o $# -lc libProt.a
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ)
depend: dep
dep:
makedepend -- $(CCFLAGS) -- $(INCLUDES) $(SRC)
clean:
rm -f $(OBJ) $(OUT)
You can't link libraries to your static library that you're creating. A static library is just a collection of object files packed into an archive.
If libProt is something that you produce yourself and have object files for you could perhaps add them in your ar command to "combine" these two static libraries.

Creating a FORTRAN makefile

I have a FORTRAN source code consisting of many different .F and .h files. I need to build an executable from it, but I'm having some problems. The makefile that I produced so far (which may have errors as I'm new to this) is:
# compiler
FC = /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons
# link flags
FLFLAGS = -g -fbacktrace
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F)) \
$(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FCFLAGS) $# $<
%.o: %.F
$(FC) $(FLFLAGS) -o $# $<
%.mod: %.h
$(FC) $(FLFLAGS) -o $# $<
clean:
rm -f *.o *.mod
When I try to make the program, however, I'm getting a slew of undefined reference errors. I mean, every function and subroutine call in the very first compiled .F file gives back an undefined reference error. I thought this was because gfortran was trying to link the files instead of just compiling them and then linking at the end, but I thought the '-c' option was supposed to prevent that.
UPDATE:
As commenters have pointed out, I mixed up the compile and link flags. Furthermore, you shouldn't compile *.h files. Here is the latest, corrected makefile:
# compiler
FC = /usr/bin/gfortran-4.4
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check -std=legacy
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $<
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Now when I run make, it will compile each *.F file in the code, but it fails at the linking stage. I get a bunch of undefined reference errors in the very first *.F file. The compiler seems to be going over each *.F file individually in the linking stage, which I'm not sure is correct. Then I get an error:
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/libgfortranbegin.a(fmain.o): In function `main':
(.text+0x26): undefined reference to `MAIN__'
collect2: ld returned 1 exit status
However, if I type the command:
gfortran -o blah *.o
The executable will be built, so it seems like I did something wrong in the makefile for the linking stage.
UPDATE: 5/9/2011
Sverre pointed out the final problem with my makefile. In my first target that builds the program, I use the shortcut command for only the first dependency ($<), but I need to include all dependencies (i.e. all *.o files) using the ($^) shortcut. The final, working makefile is as follows:
# compiler
FC := /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# $(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = vipre
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $^
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
# %.mod: %.h
# $(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Are you using GNU make? If so,
$(FC) $(FLFLAGS) -o $# $<
may be the culprit. $< is the name of the first prerequisite, but you want all the *.o files. Try using $^ instead.

Resources