What is the meaning of this makefile syntax %IDLINC% - makefile

I am trying to build a library for IDL however I am running into a lot of troubles. I believe understanding this line of syntax could help lead me to solve my bigger problems.
From what I know. The source code is written in fortran (I think?). There is the where the syntax first appears:
FOPTIONS_SHARED_win64_mingw=-I%IDLINC% -fno-second-underscore -static
I believe this FOPTIONS variable plays in a role in the building of a shared library file (.dll). What does this line mean? In particular, what exactly is %IDLINC% ?(double percent signs) I see it appear quite a bit in the warning messages.
And here is a little snippet of the compile/link code from the makefile which uses the FOPTIONS variable:
all.help:
#more $(HELPDIR)/Help.all
all: all.$(OS).$(ENV)
all..:
echo "Missing OS and ENV variables"
all.linux32.intel32: all.build
all.linux32.gnu32: all.build
all.linux32.pgi32: all.build
all.linux64.intel32: all.build
all.linux64.intel64: all.build
all.linux64.gnu32: all.build
all.linux64.gnu64: all.build
all.linux64.pgi64: all.build
all.linux64.gfortran64: all.build
all.win32.cygwin32: all.build
all.win64.cygwin64: all.build
all.win32.mingw: all.build
all.win64.mingw: all.build
all.mach.gnu32: all.build
all.sunos.sparc32: all.build
all.sunos.sparc64: all.build
all.sunos.gnu32: all.build
all.sunos.gnu64: all.build
all.build: version.fortran ntime_max
#cd $(SOURCEDIR); \
cp wrappers_$(WRAPPER_$(OS)_$(ENV)).inc wrappers.inc;\
echo "Building non-sharable object \
onera_desp_lib_$(LIBNAME_$(OS)_$(ENV)).$(NONSHAREDEXT_$(OS))"; \
$(FC_$(OS)_$(ENV)) $(FOPTIONS_NONSHARED_$(OS)_$(ENV)) *.f;\
$(AR) $(AROPTIONS_$(OS)) liboneradesp_$(LIBNAME_$(OS)_$(ENV)).$(NONSHAREDEXT_$(OS)) *.o;\
$(RANLIB) liboneradesp_$(LIBNAME_$(OS)_$(ENV)).$(NONSHAREDEXT_$(OS));\
echo "non-sharable object built";\
echo "";\
echo "Building sharable object \
onera_desp_lib_$(LIBNAME_$(OS)_$(ENV)).$(SHAREDEXT_$(OS))"; \
$(FC_$(OS)_$(ENV)) $(FOPTIONS_SHARED_$(OS)_$(ENV)) $(PIC_$(OS)_$(ENV)) -o
onera_desp_lib_$(LIBNAME_$(OS)_$(ENV)).$(SHAREDEXT_$(OS)) \
*.f $(LDOPTIONS_$(OS)_$(ENV));\
echo "sharable object built";\
echo "";\
echo "Building sequence achieved";
Any help would be greatly appreicated! I am a complete beginner with Makefiles.

%IDLINC% isn't makefile syntax, it's MS-DOS syntax. Variable substitution to be precise. The reason you see this in the warnings is because Make prints each command after its own pass of substitutions. Then it passes the command to the shell (MS-DOS) for actual execution, at which point IDLINC is substituted by that shell.
Since prefixed by -I in -I%IDLINC% I assume the variable is meant to hold the path to the IDL headers.

Related

How do I validate a GNU Makefile parameter exists in a string

I am trying to get this rule to work. Its totally blowing up my whole Makefile.
It should validate that the value for version the user passed exists in the PYVERSION variable.
The actual behavior is mixed because I've tried so many different things. I'm no GNU expert so I've tried ${version} and $(version) and $version and the same things for PYVERSION. The current version I've posted here always goes to the else block, not matter the version input.
PYVERSIONS := "3.5 3.6 3.7 3.8"
.PHONY: venv
venv:
if test $(findstring ${version}, $(PYVERSIONS)); then
/Library/Frameworks/Python.framework/Versions/${version}/bin/python3 -m venv venv
else
$(error Bad python version given (${version}) project only supports ${PYVERSIONS})
fi;
calling it like make venv version=3.5 should successfully execute the if block and create the venv.
calling it like make venv version=2.7 should raise the error message in the else block.
I was trying to follow this post
Update
With help from #Beta, this is the final solution I got to work.
PYVERSIONS := "3.6 3.7 3.8"
PYPATH := /Library/Frameworks/Python.framework/Versions
.PHONY: venv
venv:
#if test $(findstring ${version}, $(PYVERSIONS)) ; \
then \
echo "Creating virtual environment for python ${version}"; \
$(PYPATH)/${version}/bin/python3 -m venv venv; \
else \
echo "Unsupported python version (${version}). Project supports $(PYVERSIONS)"; \
fi
Actually disagree with #Beta here. Since the answer is known before you even start executing the recipe, $(error …) is the clear way to go.
Now, make stores the entire recipe as a single recursively expanded variable. When make decides to build venv (for instance, you type make venv), it will expand the entire recipe, before passing each resulting line one-by-one to fresh instances of the shell.
Thing is, when make expands your recipe,
it always expands $(error Bad python version given …), and make stops even before calling the shell.
How do we get around this?
PYVERSIONS := 3.6 3.7 3.8
PYPATH := /Library/Frameworks/Python.framework/Versions
pyversion = $(or $(filter ${version},${PYVERSION}),$(error $$version [${version}] must be exactly one of ${PYVERSIONS}))
.PHONY: venv
venv:
echo "Creating virtual environment for python ${version}"
$(PYPATH)/${pyversion}/bin/python3 -m venv venv
So,
You type make venv
Make expands the recipe
Make expands pyversion
Make expands $(filter ${version},3.6 3.7 3.8)
If you have not set version on the command-line or environment to one of the three blessed strings,
make stops there and then with a helpful message NICE
OTOH if it has been set appropritely, make is happy and starts executing the recipe
Other nice characteristics:
No shell syntax
The exit code of python3 is returned to make (a big hole in your original recipe imho).
Things always look better in make rather than the shell.
You are mixing shell syntax with Make syntax.
If you want to handle this with a shell conditional, you must put the whole thing on one line in the recipe (since each line executes in its own subshell):
venv:
if test $(findstring ${version}, $(PYVERSIONS)) ; then echo $(version)/bin/python3 venv; else echo bad version $(version); fi
or you can wrap the line by means of backslashes:
venv:
if test $(findstring ${version}, $(PYVERSIONS)) ; \
then \
echo $(version)/bin/python3 venv; \
else \
echo bad version $(version); \
fi
(Note that there is only one TAB, in front of if.)
If you want to use a Make conditional within the rule:
venv:
ifeq ($(findstring ${version}, $(PYVERSIONS)),)
echo bad version $(version);
else
echo echo $(version)/bin/python3 venv;
endif
If you want to use the Maker error command, you have a problem. Make will evaluate the conditional before executing any rule, so if you use error, then if no valid version number is given, Make will throw the error even if venv was not the target. It is possible to use error, but it's a pain, so you must first decide whether the effect is worth the price.

Must load modules before making target

I need to ensure that certain modules are loaded for the build process to proceed. I need one Makefile that can make one or several programs (submodel).
What I have currently:
all : submodel_01 submodel_02 submodel_03
check-modules: load_modules.sh
#if [ -z "${MODULES_LOADED}" ]; then \
echo "Please run"; \
echo "source $<"; \
echo "first."; \
exit 1; \
fi
.PHONY: check-modules
load_modules.sh:
#echo "export MODULES_LOADED=yes" > $#
#echo "module load intel-compiler" >> $#
#echo "module load openmpi" >> $#
submodel_01: check-modules
<command to make submodel_01>
submodel_02: check-modules
<command to make submodel_02>
submodel_03: check-modules
<command to make submodel_03>
This kinda works, but it's not very elegant. I'd much rather have make load the modules itself, then run a child make process where the modules are loaded.
I want to ensure though that the original intended target is preserved. So if I run just make, then it should make all three submodels, but if I specify a specific target, it should only make that one.
Thanks
Disclaimer: I'm not MPI expert, and I was not able to test.
I believe that for the module load command to work, it has to be executed by the parent process (before running Makefile), or in the same shell that will need the environment.
Given that each separate action in running in a separate shell, I think that the following will NOT work - the setting will not pass to the 2nd command. (Suggest you give it a try, just in case.)
submodel_01:
source load_modules.sh
<command that depends on modules>
However, this should work
submodel_01:
source load_modules.sh ; <commands that depends on modules.sh>
You can even include the 'guard' in load_modules.sh to prevent repeated sourcing by changing load_modules.sh to:
if [ ! "$MODULES_LOADED" ] ; then
module load intel-compiler"
module load openmpi
export MODULES_LOADED=yes"
fi

Automake variables resolution

I am a newbie and I am trying to learn from sourcecodes. Now I have problem understanding (for learn!) autotools: here I have some variables. In this following variable declaration-assignment
mousepad_CFLAGS = \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS) \
$(GTHREAD_CFLAGS) \
$(GTKSOURCEVIEW_CFLAGS) \
$(PLATFORM_CFLAGS) \
-DMOUSEPAD_GSETTINGS_SCHEMA_DIR=\""$(datadir)/glib-2.0/schemas"\"
The variables GLIB_CFLAGS GTK_CFLAGS GTHREAD_CFLAGS GTKSOURCEVIEW_CFLAGS PLATFORM_CFLAGS were not declared. From where their origins?
Also at the bottom there is another undeclared variable reference:
#GSETTINGS_RULES#
Those variables are defined by the configure script when it is run (depending on what configure found and where) and then those variable definitions are inserted into the Makefile generated from Makefile.in.

Makefile conditional error

I am attempting to do a make statement to check the architecture. I am very close to getting it to work:
test:
ifeq ("$(shell arch)", "armv7l")
echo "This is an arm system"
else
echo "This is not an arm system."
endif
I have one issue: although this seems to resolve to ifeq ("i386", "armv7l") which should be false, I get the following error:
$ make
ifeq ("i386", "armv7l")
/bin/sh: -c: line 0: syntax error near unexpected token `"i386",'
/bin/sh: -c: line 0: `ifeq ("i386", "armv7l")'
make: *** [test] Error 2
So, it is resolving to two strings comparing to each other, but there is a syntax error. What's wrong here?
You cannot use make statements like ifeq inside a recipe. Recipes (the lines that begin with TAB) are passed to the shell. The shell doesn't understand ifeq; that's a make construct.
You'll have to use shell if-statements inside a recipe. And, you don't have to use $(shell ...) in a recipe, because you're already in a shell.
test:
if [ `arch` = armv7l ]; then \
echo "This is an arm system"; \
else \
echo "This is not an arm system."; \
fi
This is likely not the best way to handle this, but since you didn't provide any info on what you're really trying to do with this it's all we can say.
As MadScientist said, make is passing the ifeq lines to the shell, but if you write it properly, you can definitely mix make constructs like ifeq with commands within a recipe. You just need to understand how make parses a Makefile:
If a line begins with a TAB, it is considered a command for the shell regardless of where the line is within the file.
If it doesn't begin with a TAB, make interprets it as part of its own language.
So, to fix your file, just avoid starting the make conditionals with a TAB:
test:
ifeq ("$(shell arch)", "armv7l")
echo "This is an arm system"
else
echo "This is not an arm system."
endif

gnu arm assembler command line macro fails with "Invalid identifier for .ifdef"

My toolchain is a recent version of arm-gcc.
I have a piece of code in an assembly file which must be conditionally included/assembled.
.ifdef MACRO_FROM_CMDLINE
Assembly instr1
Assembly instr2
.endif
Encapsulated code is a recent addition.
I have tried both:
gcc -x assembler-with-cpp --defsym MACRO_FROM_CMDLINE=1 <along with other necessary options>
gcc -x assembler-with-cpp -D MACRO_FROM_CMDLINE=1 <along with other necessary options>
The -D results in "Invalid identifier for .ifdef " and ".endif without .if" errors.
The --defsym results in "MACRO_FROM_CMDLINE=1 : No such file or directory", "unrecognized option --defsym" errors.
The gcc binary drives the compilation process by invoking a number of other programs in sequence to actually perform the various stages of work (compiling, assembling, linking).
When you say:
gcc -x assembler-with-cpp -D MACRO_FROM_CMDLINE=1 ...
you are asking it to run the source through the C preprocessor, and then run the result through the assembler.
The C preprocessor step will turn:
.ifdef MACRO_FROM_CMDLINE
into:
.ifdef 1
before passing it to the assembler, which then can't make sense of it. This is why you get the "invalid identifier" error. It also explains why using C preprocessor #ifdef fixes the problem.
--defsym doesn't work because it's an option to the assembler, not the gcc driver program. (The gcc driver does understand and pass through some options to some of the programs it invokes, but not all.)
You can, however, pass arbitrary options through to the assembler using the
-Wa,option[,option...]
syntax, which tells the gcc driver to pass those option(s) through to the assembler (as a list of space-separated options).
For example:
gcc -x assembler-with-cpp -Wa,--defsym,MACRO_FROM_CMDLINE=1 ...
adds
--defsym MACRO_FROM_CMDLINE=1
to the list of options passed to as when gcc invokes it, and that's how to make your original .ifdef example work.
You can see the individual programs invoked by gcc, and the options it actually passes to them, by adding the -v option.
In this case, you should see something called cc1 (the actual GCC C compiler binary) invoked with the -E flag (preprocess only) to preprocess the input to a temporary file, and then as invoked on the temporary file to assemble it.
Strange, but it it turns out I needed to use the C syntax in the assembly file.
#ifdef MACRO
Assembly Instruction
Assembly Instruction
#endif
And the macro had to be passed using the -D option.

Resources