Can't use LAPACK in makefile - 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)

Related

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

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)

Compiling SDL project on Raspberry Pi

I am trying to build a project with make (gcc on Raspbian)
Here is the makefile (I removed some unnecessary parts):
objects = 3d.o Affichage.o [...]
cflags = -I/usr/local/include/SDL2 -L/usr/local/lib -lSDL2
poly : %(objects)
gcc $(cflags) $(objects) -o poly
($objects) : types.h
[...]
When running Make, I got:
cc -c -o Affichage.o Affichage.c
fatal error: SDL.h: No such file or directory
#include <SDL.h>
I checked the folders, everything seems ok. SDL.h is indeed in /usr/local/include/SDL2. I tried to remove options one by one in cflags, no luck...
What am I missing?
Make told you exact command it tried to execute:
cc -c -o Affichage.o Affichage.c
This don't have -I path, which is the source of an error.
You have target for your resulting executable but not for object files. Make have builtin rule to compile object files from C sources, but it isn't aware of your cflags variable. So far your options are:
Define your own pattern rule
e.g:
%.o: %.c
gcc $(cflags) -c $< -o $#
However, your cflags contains -lSDL2, which is linking flag, which should be specified only on linking phase (so technically it isn't cflag). Move it to separate variable (usually LIBS, which may then be enfolded into make's semi-standard LDFLAGS).
Use variables that make is aware of
In that case, it is CFLAGS:
CC:=gcc
CFLAGS:=-I/usr/local/include/SDL2
LIBS:=-lSDL2
LDFLAGS:=-L/usr/local/lib $(LIBS)
objects:=3d.o Affichage.o
poly: $(objects)
$(CC) $^ -o $# $(LDFLAGS)
$(objects): types.h
The rest will be done by implicit rules.

Error on makefile with threads and my library

So I have been searching and looking for something that could help me with the Makefile, but I did not find anything, so thats why I am here.
My makefile right now is like this:
CC = gcc
CFLAGS = -Wall
LDFLAGS += -L$(LIBB)
LDFLAGS += -static lib1.h
LDLIBS = -lm -lpthread -lrt -l
SOURCES=lib1.c prac3.c prac3_reader.c
LIBRARIES=lib1.o
INCLUDES=lib1.h
PROGRAMS=prac3 prac3_reader
all: $(OBJS) $(PROGRAMS)
$(PROGRAMS): $(LIBRARIES) $(INCLUDES)
$(CC) $(LDFLAGS) $(LIBRARIES) $(LDLIBS) $#.o -o $#
%.o: %.c $(INCLUDES)
$(CC) $(CFLAGS) -o $# -c $<
clean:
rm -rf *.o *~ $(PROGRAMS)
I know there are probably a lot of things that can be removed, but I do not really know which ones are. I have two programs called
prac3.c
and
prac3_reader.c
Also, I have my own library called
lib1.c
and also compiled like
lib1.h
When I go to my directory with the terminal and use the command make I recive this error:
gcc -L -static lib1.h lib1.o -lm -lpthread -lrt -l prac3.o -o prac3
/usr/bin/ld: no se puede encontrar -lprac3.o
collect2: error: ld returned 1 exit status
Makefile:15: recipe for target 'prac3' failed
make: *** [prac3] Error 1
I am running on Ubuntu.
The -l flag expects an argument. When it is combined in the gcc statement it causes the prac3.o argument to be considered as the name of a library. There is no such library prac3.o, so you get the error.
In general .o files aren't "libraries". They are object files. Remove the -l flag and you will be fine.
"libraries" are generally .a or .so files from a library path - but even then, you wouldn't specify the suffix (.e.g "-lpthreads").

Makefile with multiple directories

I wanted to write a makefile for a program that has source files located in different directories, the structure is:
--root(here will be makefile)
--src:
--main.c
--include:
--here are 6 .h files, that are used by other .c files, main.c includes on all of them
--operacje
--suma.c
--iloczyn.c
--roznica.c
--reszta:
macierz.c
--we_wy:
--rest of the .c files
most of .c files include at least one .h file. This is what I wrote so far:
VPATH=./src:./src/include:./src/operacje:./src/reszta:./src/we_wy
CLFAGS = -Wall
CC = gcc
INCLUDE = -I src/include
NAME = macierze
FILE_SOURCE := pliki.c wczytaj_plik.c wypisz_plik.c
CONSOLE_SOURCE := wczytaj_konsola.c wypisz_konsola.c
OTHER_SOURCE := suma.c roznica.c iloczyn.c macierz.c
HEADERS := suma.h roznica.h iloczyn.h wypisz.h wczytaj.h macierz.h
FILE_OBJECTS := $(FILE_SOURCE:.c=.o)
CONSOLE_OBJECTS := $(CONSOLE_SOURCE:.c=.o)
OTHER_OBJECTS := $(OTHER_SOURCE:.c=.h)
%.o: %.c %.h
gcc $(CFLAGS) $(INCLUDE) -c $?
%.o: %.c
gcc $(CFLAGS) $(INCLUDE) -c $? -o $#
finput: HEADERS+=pliki.h
finput: $(FILE_OBJECTS) $(OTHER_OBJECTS) main.o
gcc $(CFLAGS) -o $(NAME) $^ -D WEWY_PLIKI
main.o: main.c $(HEADERS)
gcc $(CFLAGS) $(INCLUDE) -c src/main.c
clean:
rm -rf *.o
The goal is, to make compiled program run a bit differently based on make , hence the -D option and adding
finput: HEADERS+=pliki.h
this finput is the first of the 4 possible options. Each option will be using slightly different set of .c and .h files
Now, when I do
make finput
i get the listing:
gcc -I src/include -c ./src/we_wy/pliki.c ./src/include/pliki.h
gcc -I src/include -c ./src/we_wy/wczytaj_plik.c -o wczytaj_plik.o
gcc -I src/include -c ./src/we_wy/wypisz_plik.c -o wypisz_plik.o
gcc -I src/include -c src/main.c
gcc -o macierze pliki.o wczytaj_plik.o wypisz_plik.o ./src/include/suma.h ./src/include/roznica.h ./src/include/iloczyn.h ./src/include/macierz.h main.o -D WEWY_PLIKI
wczytaj_plik.o: In function `wczytaj':
wczytaj_plik.c:(.text+0x5f): undefined reference to `macierz_alokuj'
main.o: In function `main':
main.c:(.text+0x7e): undefined reference to `suma'
<and other undefined references in main>
I noticed few errors:
1. it doesen't produce .o files from $(OTHER_OBJECTS)
2. there is no -Wall option from $(CFLAGS)
3. and of course it doesen't complete.
I would be grateful for some info, what am I doing wrong.
OTHER_OBJECTS := $(OTHER_SOURCE:.c=.h)
If this is not a typo, it is the explanation for (1.). You rename the files to header files, and the header files are found in VPATH and have no remake rules, so they are included verbatim in $^. Try $(OTHER_SOURCE:.c=.o).
CLFAGS = -Wall
Try CFLAGS instead.
Just to point out that this:
finput: HEADERS+=pliki.h
...
main.o: main.c $(HEADERS)
will not do what you want it to do. Target-specific variables only are in effect inside the recipes of child targets. They do not have any impact on the prerequisite lists (for example).
I urge you to look into methods of automatically generating make dependencies: this is far more efficient (and accurate) than trying to maintain them by hand within the makefile.

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