Strange compilation error triggered by exchanging the FCFLAGS and FLFLAGS variables

Hi,

I can compile the mstar project, https://github.com/rubel75/mstar.git with the makefile shipped in the repo. But I noticed that the FCFLAGS and FLFLAGS should be interchanged in the
makefile for the mstar code located at:
https://github.com/rubel75/mstar/blob/8a0c5aba2902c7ba3c662108616c6b0d530e4104/makefile#L17.

The original content is as follows:

FCFLAGS = -L${MKLROOT}/lib/intel64 -lmkl_intel_ilp64 -lmkl_sequential
-lmkl_core -lpthread -qopenmp -ldl
FLFLAGS = -i8 -I${MKLROOT}/include -qopenmp

As a traditional convention, the second letter of the make variable is
probably selected to help the user remember: ā€˜Cā€™ for ā€œcompilerā€ and
ā€˜Lā€™ for linker.

And this can also be verified with the mkl_link_tool, which will some
results as below for my case:

werner@X10DAi:/opt/intel/mkl/bin$ ./mkl_link_tool -interactive
[snipped]
Output
======

Compiler option(s):
-i8 -I${MKLROOT}/include

Linking line:
-L${MKLROOT}/lib/intel64 -lmkl_intel_ilp64 -lmkl_sequential
-lmkl_core -lpthread -lm -ldl

Environment variable(s):
export LD_LIBRARY_PATH=${MKLROOT}/lib/intel64:$LD_LIBRARY_PATH;

Based on the above output of mkl_link_tool, Iā€™ve tried with the following revisions in the makefile:

#Use this link line:
FLFLAGS = -L${MKLROOT}/lib/intel64 -lmkl_intel_ilp64 -lmkl_sequential
-lmkl_core -lpthread -lm -ldl
#Compiler options
FCFLAGS = -i8 -I"${MKLROOT}/include"

But the make command failed with the following errors:

ld: eigvs.o: in function `eigvs_':
eigvs.f90:(.text+0x2a9): undefined reference to `ssyevd_'
ld: eigvs.f90:(.text+0x7e1): undefined reference to `ssyevd_'
ld: eigvz.o: in function `eigvz_':
eigvz.f90:(.text+0x398): undefined reference to `cheevd_'
ld: eigvz.f90:(.text+0xaea): undefined reference to `cheevd_'
make: *** [makefile:38: mstar] Error 1

Any hints for this problem will be highly appreciated.

Regards,
HY

Hi @Hongyi, welcome to the Discourse!

I agree, the choice of variable naming appears to be the wrong way around in that makefile according to convention.

When you switched the variable definitions at the top of the makefile, did you also switch the use of the variables further down in the makefile, on lines 32 and 35?

e.g.

FLFLAGS = -L${MKLROOT}/lib/intel64 -lmkl_intel_ilp64 -lmkl_sequential
-lmkl_core -lpthread -qopenmp -ldl
FCFLAGS = -i8 -I${MKLROOT}/include -qopenmp
all: $(PROGRAM)

$(PROGRAM): $(SRCS)
	$(FC) $(FLFLAGS) $(FLINK) -o $@ $^

%.o: %.f90
	$(FC) $(FCFLAGS) $(FOPT) -c $<
1 Like

@lkedward Good catch, and you caught the crux of the problem. It does the trick. Thanks a lot.

Regards,
HY

Do you know where I can find an official document explaining these variables?

Regards,
HY

all you need is to understand the difference between compiling and linkingā€¦
process of going from source to object is compilationā€¦ move from object to executable linking.
and what you need to pass for each stageā€¦

the names of the variables is irrelevant in this caseā€¦ the makefile author could have used DOG and BIRD, would have been strange but did not make any difference

1 Like

@alin Got it. Basically they are the self customized variables used in Makefile, and you can use any reasonable variable name, as long as they are consistent throughout the Makefile. Thank you again for clearing my doubts.

Regards,
HY

FCFLAGS stands for Fortran Compilation Flags.

FLFLAGS stands for Fortran Linking Flags.

Typically, FCFLAGS had a -c option, meaning ā€œcompile, but do not linkā€, and FLFLAGS had -L and -l options, specifying libraries if needed, and an -o flag specifying the name of the executable. Sometimes, the -s flag (strip) and the -t flag (make it sticky) were also used, typically on Unix systems.

1 Like

Whatā€™s the underlying workflow mechanism for strip and sticky you mentioned above?

An executable can contain code not required for normal execution. Typically this is information useful for debugging. So once a program is ready for production use you can tell the compiler to remove this code. The resulting binary will be smaller and save space. This is not nearly as important as it once was because disk space and network speeds are orders of magnitude larger and faster.

When the compiler is told at compile time to generate code with no unneeded symbols it can potentially produce faster code as well.

Stripping after compilation is still done by a number of COTS codes because it makes it harder for someone to disassemble code into a higher level language and so makes it harder to ā€œreverse engineerā€ the code, but otherwise I rarely see it used myself.

You can still strip a code after loading on Unix-like systems with the strip(1) command. The penalty you pay is generally the tracebacks and some debug messages will be less useful and will not contain names you recognize but will be mangled names or addresses. I would be surprised if it gave any performance gain when done after compilation. You might see a (probably trivial) reduction in the static memory size required to start up your program (which you can check with the size(1) command).

As you can guess from the fact there is a command such as strip(1) that this was far more useful in the past than it is today when even a PC might have a TeraByte of disk. I used to use the strip(1) command on a regular basis but have not used it in years. Note that if you use some of the options on the strip(1) command casually without being intimately aware of what they mean you will probably make your executable useless, even though using it without options is basically harmless.

I get frustrated by commercial codes that strip their binaries because it makes it considerably harder to determine the cause of bugs in isolated circumstances where it is not feasible to send the offending input models to the vendor as a reproducer, but stripping commercial codes is the last common use of strip(1) I am personally aware of.

Note stripping an executable does not mean you cannot still disassemble it, but it means the disassembled code (typically machine code) will typically use nearly random names for all the variables. The original symbol names used in the code often contained in the stripped information can act as comments giving a human a much better idea of what the purpose of the code is, so removing the symbol information is considered worth it for big commerical software providers, even though as a side effect it can make their product harder to work with when bugs are encountered by a customer.

Also note the file(1) command will often tell you if a binary file is already stripped or not.

1 Like

Had not done it myself in a while, so here is an actual use of strip(1). It took an 8.5M file
down to about 5M, did not change the memory load size at all, and I did not test for changes
in performance. So unless you have a binary that is copied and moved or transferred a LOT
I really cannot recommend it now-adays.

-rwxrwx--x 1 urbanjs urbanjs 8546200 Aug 21 22:19 c2b
$ file c2b
c2b: ELF 64-bit LSB shared object,
     x86-64,
     version 1 (SYSV),
     dynamically linked,
     interpreter /lib64/ld-linux-x86-64.so.2,
     BuildID[sha1]=55608a24aa9c24ae1056e0feaa15e797e1d9e6d5,
     for GNU/Linux 3.2.0,
     with debug_info,
     not stripped
$ size c2b
   text    data     bss     dec     hex filename
4679008  487208 28168184        33334400        1fca480 c2b

$ strip c2b

ls -ld c2b
-rwxrwx--x 1 urbanjs urbanjs 5193352 Oct 19 23:28 c2b
$ size c2b
   text    data     bss     dec     hex filename
4679008  487208 28168184        33334400        1fca480 c2b
$ file c2b
 c2b: ELF 64-bit LSB shared object,
 x86-64,
 version 1 (SYSV),
 dynamically linked,
 interpreter /lib64/ld-linux-x86-64.so.2,
 BuildID[sha1]=55608a24aa9c24ae1056e0feaa15e797e1d9e6d5,
 for GNU/Linux 3.2.0,
 stripped

| urbanjost
October 20 |

  • | - |

An executable can contain code not required for normal execution. Typically this is information useful for debugging. So once a program is ready for production use you can tell the compiler to remove this code. The resulting binary will be smaller and save space. This is not nearly as important as it once was because disk space and network speeds are orders of magnitude larger and faster.

When the compiler is told at compile time to generate code with no unneeded symbols it can potentially produce faster code as well.

Stripping after compilation is still done by a number of COTS codes because it makes it harder for someone to disassemble code into a higher level language and so makes it harder to ā€œreverse engineerā€ the code, but otherwise I rarely see it used myself.

Whatā€™s the meaning of ā€œCOTSā€?

COTS = Commercial off-the-shelf

| ivanpribec
October 20 |

  • | - |

COTS = Commercial off-the-shelf

Got it. Thank you.