Makefile produces for Fortran 90 causes unresolved external symbol - makefile

My program is an mpi program which uses intel MKL. for simple, let us assume there are main.f90 a.f90 b.f90 in which a.f90 contains module called mymod needed by others
Usually I will compile it like this
mpiifort *90 /fast /Qmkl /MD -o main.exe
I just do it twice, because for the first time, there will be lack of mymod.mod
Now I want to use makefile, since I want to reduce recompiling time. I write it like this
IFORT = /fast
MKL =/Qmkl
LDFLAGS = /MD
main:main.obj b.obj
mpiifort $(IFORT) $(MKL) $(LDFLAGS) $< -o $#
mymod.mod:a.f90
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
main.obj:main.f90
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
b.obj:b.f90
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
However, there must be something wrong here. I got bunch of unresolved external symbol. What is wrong?

Firstly somebody else can probably write a better/more complete answer (or direct us to one) and I would welcome this, but below I provide a very simple example.
Now we can identify the (probable) source of the errors : If we replace the compilation command with just touch we can produce a simple example that demonstrates the issue
main:main.obj b.obj
touch $#
mymod.mod:a.f90
touch $#
main.obj:main.f90
touch $#
b.obj:b.f90
touch $#
If we then construct our "source files" with
>touch main.f90 b.f90 a.f90
we can then try to build our main executable:
>make main
which will output:
touch main.obj
touch b.obj
touch main
Note how this does not create the mymod.mod file. This means that in your case a.f90 does not get compiled when you build main and hence the required symobols are not available (i.e. when linking there are functions/routines etc. that are undefined as a.obj is not available). If we now show that main depends on mymod.mod by adjusting our makefile to be
main:main.obj b.obj mymod.mod
touch $#
mymod.mod:a.f90
touch $#
main.obj:main.f90
touch $#
b.obj:b.f90
touch $#
we can now try building main (after first cleaning up by doing rm *.obj mymod.mod main) and we get:
>make main
touch main.obj
touch b.obj
touch mymod.mod
touch main
So we have successfully got make to build the mymod.mod target as a part of building main. Note that in reality you probably want to ensure that some targets get built before others (e.g. here you probably want to compile a.f90 before b.f90). You can do that with dependency lists, which you may wish to auto-generate (see for example this question).

I figure out a way that is kind of automatic if we use intel fortran
Intel fortran provides an option called gen-dep, it will automatically analysis and output dependency information can be used for makefile. So just running the following command, if there is error message due to missing mod file, just run it twice
mpiifort *90 /Qmkl /gen-dep > dependency.txt
we got dependency.txt. Open it, we will find something like this
mpifc.bat for the Intel(R) MPI Library 5.1.2 for Windows*
Copyright(C) 2007-2015, Intel Corporation. All rights reserved.
mymod.mod : \
a.f90
a.obj : \
a.f90
b.obj : \
b.f90 mymod.mod
main.obj : \
main.f90 \
c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi_base.mod \
c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi_sizeofs.mod \
c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi_constants.mod \
c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi.mod \
mymod.mod
Microsoft (R) Incremental Linker Version 14.00.23026.0
Copyright (C) Microsoft Corporation. All rights reserved.
-out:a.exe
-subsystem:console
"-libpath:c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mkl\lib\intel64_win"
"/LIBPATH:c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\lib\release_mt"
"/LIBPATH:c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\lib"
impi.lib
a.obj
b.obj
main.obj
Those module related to mpi are static so just remove it. After some simple text manipulation(using regex would be a good choice) to make it more clear and compact, we can get a correct makefile like this(I have fixed some errors in my question post)
IFORT = /fast
MKL =/Qmkl
LDFLAGS = /MD
a: a.obj b.obj main.obj
mpiifort $(IFORT) $(MKL) $(LDFLAGS) $^ -o $#.exe
mymod.mod : a.f90
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
a.obj : a.f90
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
b.obj : b.f90 mymod.mod
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
main.obj : main.f90 mymod.mod
mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<

Related

Why does f77 -f fail and what should it do?

I am trying to run some old Fortran code of my project team in ubuntu 16.04. I have not done any modifications to the existing code.
All I have done is installed gfortran, opened a terminal, and went to the file location using "cd" command. Here I have many files, but just consider this three, a script file compile.sh, and two makefiles counter.make and remail.make.
In compile.sh
make -f counter.make
make -f remail.make
In counter.make
SOURCE_APPLI=../SOURCES_COUNTERFLOW/
SOURCES_f77 = $(SOURCE_APPLI)table.f
TARGET = unst.e
OBJECTS = $(SOURCES_f77:.f=.o)
COMPILE = f77 -f
.f90.o :
$(COMPILE1) -o $*.o -c $*.f90
.f.o :
$(COMPILE) -o $*.o -c $*.f
$(TARGET) : $(OBJECTS)
$(COMPILE) $(OBJECTS) -o $#
del :
$(DELETE) $(OBJECTS)
In remail.make
SOURCE_APPLI= ../SOURCES_COUNTERFLOW/
$(SOURCE_APPLI)grcom.f
TARGET = remail.e
OBJECTS = $(SOURCES_f77:.f=.o)
COMPILE = f90
.f90.o :
$(COMPILE) -o $*.o -c $*.f90
.f.o :
$(COMPILE) -o $*.o -c $*.f
$(TARGET) : $(OBJECTS)
$(COMPILE) $(OBJECTS) -o $#
del :
$(DELETE) $(OBJECTS)
When I run compile.sh, I got an error as shown below
f77: error: unrecognized command line option ‘-f’
counter.make:29: recipe for target 'unst.e' failed
make: *** [unst.e] Error 1
make: 'remail.e' is up to date.
So my question is what is the difference with and without using -f option in the f77 command line?
The f77 manual page at https://www.unix.com/man-page/v7/1/f77/ says
-f Use a floating point interpreter
(for PDP11's that lack 11/70-style floating point).
If you are not on a PDP-11, it appears that this option would perhaps not be useful at all in the first place.
Probably still review the local documentation, ideally for the system where this set of Makefiles was once created.
GNU Fortran 77 appears to use this option to specify various language options, but then it would not be useful on its own (it takes arguments like -fdollar-ok to enable something called "dollar ok", for example. See the linked manual for an extensive list of these options and their meaning).

how to convert old visual c++ code (vc++ 6.0) to visual studio 2019, libc missing

I have some old Visual C++ (v 6.0) code that runs as a CLI application and builds with an nmake file, that I would like to convert to something I can build (in a shell window not under the IDE) in Visual Studio 2019. It uses a library I build similarly. My makefiles will be included at the bottom.
I found
c:\program files (x86)\microsoft visual studio 14.0\common7\tools\vsvars32.bat
and with that I can run nmake as I need (I have a .bat file that builds about 30 of these programs as a kind of testbase for the tool and its library and I run it within Emacs and compare the outputs to the last time I ran it, expecting the only differences to be date time stamps, compiler versions, and the ilk.)
However, when I get to the linking stage, I get the error
LINK : fatal error LNK1104: cannot open file 'LIBC.lib'
I looked in the relevant lib directory and found lots of variants of libcxxx.lib but no plain libc.lib. I don't know if the issue is command line arguments I have passed to CL or something else. Hence, this question.
# makefile for prog (a hello world type example)
DEFINES=
INCLUDES= -I. -I.\inc.vc -I\yxx\inc.vc -I\yxx\lib.vc
CXXFLAGS= /c /Od /W3 /Za $(DEFINES) $(INCLUDES)
CXX=cl
OBJECTS=yy_main.obj \
yy_mylex.obj \
yy_mypsr.obj
yy_main.obj: \yxx\lib.vc\yy_main.cpp yy_mypsr.h yy_err.tbl yy_syna.tbl
echo $(CXXFLAGS) >$*.OPT
$(CXX) /Fo$# #$*.OPT \yxx\lib.vc\$*.CPP >$*.ERR
TYPE $*.ERR
yy_mylex.obj: yy_mylex.cpp yy_mylex.h
echo $(CXXFLAGS) >$*.OPT
$(CXX) /Fo$# #$*.OPT $*.CPP >$*.ERR
TYPE $*.ERR
yy_mypsr.obj: yy_mypsr.cpp
echo $(CXXFLAGS) >$*.OPT
$(CXX) /Fo$# #$*.OPT $*.CPP >$*.ERR
TYPE $*.ERR
prog.exe: $(OBJECTS) \yxx\lib.vc\yy_lol.lib
CL #<<
$(OBJECTS)
\yxx\lib.vc\yy_lol.lib
/link /out:prog.exe
<<
# makefile for yy_lol.lib (lists of object files pruned to be smaller)
DEFINES= -Dyy_assert_disable_
INCLUDES= -I. -I\yxx\inc.vc -I\yxx\lib.vc
ARFLAGS=
CXXFLAGS= /c /Od /W3 /Za $(DEFINES) $(INCLUDES)
CXX=cl
AR=LIB
RM=del
OBJECTS=\yxx\lib.vc\yy_asrt.obj \
\yxx\lib.vc\yy_ast.obj \
\yxx\lib.vc\yy_bktrk.obj \
\yxx\lib.vc\yy_buf.obj \
\yxx\lib.vc\yy_sym.obj
.cpp.obj:
echo $(CXXFLAGS) >$*.OPT
$(CXX) /Fo$# #$*.OPT $*.CPP >$*.ERR
TYPE $*.ERR
yy_lol.lib: $(OBJECTS)
-$(RM) $#
-$(AR) /out:$# $(ARFLAGS) \yxx\lib.vc\yy_asrt.obj
-$(AR) $# $(ARFLAGS) \yxx\lib.vc\yy_ast.obj
-$(AR) $# $(ARFLAGS) \yxx\lib.vc\yy_bktrk.obj
-$(AR) $# $(ARFLAGS) \yxx\lib.vc\yy_buf.obj
-$(AR) $# $(ARFLAGS) \yxx\lib.vc\yy_sym.obj
As you have noticed, there is no libc as such: it depends on the linkage model you are working from
Single threaded (does not exist from VS10 onwards)
Single threaded Debug (does not exist from VS10 onwards)
Multi threaded
Multi threaded Debug
Multi threaded DLL
Multi threaded Debug DLL
It picks up a different libc depending on which model you are using. At a guess the libc came from the single threaded model (non-debug) that no longer exists.
For the same functionality, try using libcmt.lib - the multi-threaded non-debug version.

Makefile compiles all the files everytime

My Makefile compiles all the files everytime I run it though the files have not been changed. I know that this question has been asked several times but none of the provided solutions seem to work for me. I am new to Makefile and most of the times I do not understand the jargon used in the solution. Also, I want to save all the generated .o files under the folder 'obj'
Here is my folder structure
project (-)
gen (-)
display (-)
.c and .h files
logic (-)
.c and .h files
lib (-)
include (-)
.h files
.lib files
man (-)
.c and .h files
obj (-)
want to save all the .o files here
I am running this on Windows OS using MinGW
Here is my Makefile:
ALL: demo
SRCS:= filename1.o filename2.o filename3.o filename4.o and so on till filename27.o
demo: display.o logic.o man.o
gcc $(SRCS) -lglut32 -loglx -lopengl32 -Llib -o demo
display.o:
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/display/*.c -lglut32 -loglx -lopengl32 -Llib -c
logic.o:
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/logic/*.c -lglut32 -loglx -lopengl32 -Llib -c
man.o:
gcc -Igen/display -Igen/logic -Iman -Ilib/include man/*.c -lglut32 -loglx -lopengl32 -Llib -c
clean:
#echo "Cleaning up.."
-rm -rf *.o
-rm *.exe
NOTE: glut and oglx files are present in the lib folder. Display.o, lib.o and man.o do not have corresponding .c files. They are just folder names with many c files in them.
I understand this could be the problem. As there are no display.o, logic.o and man.o files created, MAKE complies the rule associated with it eveytime. SO how do I tell it to check for the actual .o filename1.o, filename2.o etc for the timestamp and recompile ONLY if they are older than the corresponding c files and h files maybe even the lib files they depend on.
I tried the following to create dependencies and avoid compiling of files everytime. But this did not help.
%.d: %.c
#set -e; rm -f $#; \
$(CC) -M $(CFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
At a basic level, make is looking for lines like:
target: dependency
command
If target does not exist, it calls the rule for dependency and then runs command. If target does exist, it tests if dependency is newer or does not exist. If so, it calls the rule for dependency and then runs command. Otherwise, it stops.
Significantly, the rule for dependency will only be called if (a) dependency doesn't exist, or (b) dependency is newer than target.
In the question, assume we run make demo. Then make looks for the line that begins demo: and notices it declares dependencies. So it looks at each dependency in turn to see if they require action. It first discovers display.o. It notices that display.o: does not exist, so it runs the associated rule. It does the same for the other *.o.
To avoid the *.o rules always being run because no associated file exists, you could rewrite like:
ALL: demo
SRCS:= filename1.o filename2.o filename3.o filename4.o and so on till filename27.o
demo: display.ts logic.ts man.ts
gcc $(SRCS) -lglut32 -loglx -lopengl32 -Llib -o demo
display.ts: gen/display/*.c
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/display/*.c -lglut32 -loglx -lopengl32 -Llib -c
echo . > display.ts
logic.ts: gen/logic/*.c
gcc -Igen/display -Igen/logic -Iman -Ilib/include gen/logic/*.c -lglut32 -loglx -lopengl32 -Llib -c
echo . > logic.ts
man.ts: man/*.c
gcc -Igen/display -Igen/logic -Iman -Ilib/include man/*.c -lglut32 -loglx -lopengl32 -Llib -c
echo . > man.ts
clean:
#echo "Cleaning up.."
-rm -rf *.o *.ts
-rm *.exe
Problem is that your binary object targets (like display.o) do not actually match files produced by their rules. If you tell make it needs to make target display.o, it (normally, except for phony targets, but those always rerun) expect the corresponding file to be produced by the rule's recipe and it can track if the target needs to be remade. If no such file is produces, this target always evaluates as outdated and needing remaking.
A bit of a silly example of this would be the following tree:
.
├── Makefile
├── main.c
└── test
└── file.c
and Makefile:
main: test.o main.o
$(CC) -o main *.o
test.o:
$(CC) $(CFLAGX) -c test/*.c
There is no test.o file and target needs to be remade... the rule runs, produces file.o (again). Since this target was remade and is prerequisite of main... everything always gets remade.
Now with this small modification:
main: test.o main.o
$(CC) -o main *.o
test.o:
$(CC) $(CFLAGX) -o $# -c test/*.c
test.o target indeed produces test.o file and the rule needs no remaking if test.c does not change... and with test.o unchanged and main.c perhaps as well, we get:
$ make
make: 'main' is up to date.
It still is not entirely correct as it really should read:
main: test.o main.o
$(CC) -o main $+
test.o: test/*.c
$(CC) $(CFLAGX) -o $# -c $^
Where I declare depend prerequisites of test.o and reference both them and the target by automatic variable in the rule's recipe. And Same goes for prerequisites for linking. Of course in this simple example I could just rely on implicit pattern rules and do this:
main: test/file.o main.c
test/file.o: test/*.c
What does this mean for your makefile? When you compile your object files, have a look what do they actually produce and match your target to that or (with -o $# for instance) tell them to produce exactly the file matching your target.
I've extended the silly example a bit and there are now two files in test/:
.
├── Makefile
├── main.c
└── test
├── file.c
└── other.c
And the Makefile can look something like this:
main: obj/file.o obj/other.o main.c
obj/%.o: test/%.c
mkdir -p obj
$(CC) $(CFLAGS) -c -o $# $^
It now stores object files in obj/ and make still understand what needs what and can track changes. Of course your setup is more complex and will require more rules, perhaps also divining actual sources or intermediate targets from the directory tree and define few variables to work with that information, e.g.:
OBJS := $(patsubst test/%.c,obj/%.o,$(wildcard test/*.c))
main: $(OBJS) main.c
obj/%.o: test/%.c
mkdir -p obj
$(CC) $(CFLAGS) -c -o $# $^
But the principles remain the same.

how to modify a make file used by mingw so that the linker input is a file with objects?

I use Visual Studio with VisualGDB and i have around 2000 .c files
The visualgdb offers some template make files. The issue is that if there are too many files i get this windows 10 limitation error(command is too long)
process_begin: CreateProcess(C:\SysGCC\mingw32\bin\g++.exe, C:/SysGCC/mingw32/bin/g++.exe -o Debug/WindowsProject2.exe -Wl,-gc-sections -Wl,--start-group Debug/Source.o Debug/thisIsAveryLongFilenameYesSir0.o Debug/thisIsAveryLongFilenameYesSir1.o Debug/thisIsAveryLongFilenameYesSir10.o Debug/thisIsAveryLongFilenameYesSir100.o Debug/thisIsAveryLongFilenameYesSir998.o
....many files ...
Debug/thisIsAveryLongFilenameYesSir999.o -Wl,--end-group
1> Makefile:137: recipe for target 'Debug/WindowsProject2.exe' failed
1> -------------------------------------------------------------
1> Command exited with code 2
1> Executable: cmd.exe
1> Arguments: /c "C:\SysGCC\mingw32\bin\mingw32-make.exe" -j8 CONFIG=Debug
1> Directory: C:\Users\timo\Desktop\Study\Embedded\STM32\VisualGDB\WindowsProject2\WindowsProject2
1>VisualGDB : error : Command-line action failed
I found the make commands from the make file templae generated by visualGDB
ifeq ($(TARGETTYPE),SHARED)
$(BINARYDIR)/$(TARGETNAME): $(all_objs) $(EXTERNAL_LIBS)
$(LD) -shared -o $# $(LDFLAGS) $(START_GROUP) $(all_objs) $(LIBRARY_LDFLAGS) $(END_GROUP)
endif
And the support sent me 2 variants who doesnt work:
1.
ifeq ($(TARGETTYPE),APP)
$(BINARYDIR)/$(TARGETNAME): $(all_objs) $(EXTERNAL_LIBS)
#echo $(all_objs) > $#.in
$(LD) -o $# $(LDFLAGS) $(START_GROUP) #$#.in $(LIBRARY_LDFLAGS) $(END_GROUP)
endif
2.
ifeq ($(TARGETTYPE),APP)
$(BINARYDIR)/$(TARGETNAME): $(all_objs) $(EXTERNAL_LIBS)
<TAB>#echo -g > $#.in
<TAB>$(foreach obj,$(all_objs),cmd /c “echo $(obj) >> $#.in”)
<TAB> $(LD) -o $# $(LDFLAGS) $(START_GROUP) #$#.in $(LIBRARY_LDFLAGS) $(END_GROUP)
endif
Variant 1 there is on 17_01_Dev.exe.in which contains the list of objects like
Debug/file2.o Debug/file1.o …
But its limited to aprox 8190 characters and then it cuts out all the other objects
Please help :(
Finnaly it works with this !
ifeq ($(TARGETTYPE),APP)
$(BINARYDIR)/$(TARGETNAME): $(all_objs) $(EXTERNAL_LIBS)
$(file >$#.in,$^)
$(LD) -o $# $(LDFLAGS) $(START_GROUP) #$#.in $(LIBRARY_LDFLAGS) $(END_GROUP)
endif

Makefile runs over C file twice

I have two files: assign1.c and ports.h.
FYI: I am using avr-gcc.
I built the following makefile, which I also use for another project (and other TARGET) where it works fine.
TARGET = assign2
LIB=
INCLUDE=ports.h
CFLAGS =-mmcu=atmega32 -Wall
CC = avr-gcc
SRC= $(TARGET).c
OBJ= $(SRC:.c=.o)
OBJCOPY = avr-objcopy
FORMAT = ihex
MSG_COMPILING = Compiling:
MSG_LINKING = Linking:
MSG_FLASH = Creating load file for flash:
all:elf hex
elf: $(TARGET).elf
hex: $(TARGET).hex
%.hex: %.elf
#echo $(MSG_FLASH) $#
#echo
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $#
$(RM) *.elf $(TARGET)
#echo
%.elf: $(OBJ) $(LIB)
#echo $(MSG_LINKING) $#
#echo
$(CC) $(CFLAGS) $^ -o $#
#echo
%.o: $(SRC) $(INCLUDE)
#echo $(MSG_COMPILING) $<
#echo
$(CC) $(CFLAGS) -c $<
#echo
.PHONY : clean
clean:
$(RM) *.o *.hex *.elf $(TARGET)
The terminal prints the following output.
C:\Project>make
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign2.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
Linking: assign2.elf
avr-gcc -mmcu=atmega32 -Wall assign2.o -o assign2.elf
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
avr-gcc elf.o assign2.elf -o elf
avr-gcc: elf.o: No such file or directory
make: *** [elf] Error 1
rm assign2.o
C:\Project>
For some reason it seems to compile the first file, a second time and doing so crashes.
Can anyone correct me on my errors?
The problem is your pattern rules. You are writing pattern rules like this (after make expands the variables):
%.o: assign2.c ports.h
What this rule tells make is that ANY target it wants to build that matches the %.o pattern, can be built by compiling assign2.c. That's obviously not true: this rule build exactly one target: assign2.o.
So make reads your makefile and wants to build a file named elf. It sees that elf depends on $(TARGET).elf, so it builds that (that's the first compile and link, that works). Then make wants to build elf itself. You haven't declared it to be .PHONY, so make assumes it might be a real target.
Make looks through its built-in rules to find one that will let it build elf, and it finds a built-in rule: % : %.o which it can use to compile a program from a .o file with the same prefix. So now for target elf make wants to try to build a file elf.o. Oho! It sees there's a pattern rule that lets it build any .o file based on the assign2.c source file, so it runs that rule (that's the second compile) expecting it to build elf.o... which it doesn't, obviously.
Then make runs the built-in link recipe, using elf.o which doesn't exist, and fails.
The solution to your problem is two things:
First, you should always declare all your makefile targets that you don't actually want to build as .PHONY so make won't try to build them:
.PHONY: all elf hex
Second, you should never use pattern rules where the prerequisite is not also a pattern (this can be useful in certain very specific situations, but not in general). You should either change those pattern rules to explicit rules:
assign2.elf: $(OBJ) $(LIB)
...
$(OBJ): $(SRC) $(INCLUDE)
...
Or make them into full pattern rules by using the pattern in the prerequisites list as well:
%.elf : %.obj $(LIB)
...
%.o: %.c $(INCLUDE)
...

Resources