Using conditionals in a z/OS makefile - makefile

I have been successfully using z/OS make to build my application. I have now come to point in my project where I move from a debug version of the application to a "release" version, a.k.a non-debug, so my compile options and link options change.
I have been trying to use conditionals in my makefile to mean I don't have to change multiple lines in the file in order to switch between the two build modes, but I cannot find ANY examples of conditionals in z/OS make, and the small amount of documentation in the manuals about them is not enough to actually discover how to make it work. I'm hoping someone on here has managed to make them work (no pun intended) and can enlighten me.
Here's what I would like to have (snippet from makefile):-
BuildType=DEBUG
.IF ($(BuildType)==DEBUG)
CompOpts= -c -W"c,debug,LP64,sscomm,dll" -D_DEBUG
.ELSE
CompOpts= -c -s -W"c,LP64,sscomm,compress,dll"
.END
Note that I understand there are many different ways to set BuildType. This snippet has it set in-line for simplicity of asking the question. The problem at hand is the syntax of the .IF statement. I cannot make the .IF statement work. That's what I am hoping for help, or working examples of.
I have managed to get something working where I only have to edit one character in the file to switch between the two modes, but it is not by any means ideal. N.B. ANYTHING is not set to any value in the makefile.
# In the .IF clause below, if you have != it will run the DEBUG build
# and if you have == it will run the RELEASE build
.IF ($(ANYTHING)==$(NULL))
CompOpts= -c -W"c,debug,LP64,sscomm,dll" -D_DEBUG
.ELSE
CompOpts= -c -s -W"c,LP64,sscomm,compress,dll"
.END

The following syntax should work with z/OS make:
.IF $(BuildType) == DEBUG
CompOpts= -c -W"c,debug,LP64,sscomm,dll" -D_DEBUG
.ELSE
CompOpts= -c -s -W"c,LP64,sscomm,compress,dll"
.END
When you invoke the make file with:
make -DBuildType=DEBUG
it will select the debug version of compiler options, otherwise it will select the production version.

Related

how to crate a make file for verifone (vx520 or vx820)

I have a verifone terminal (vx520 and vx820).
I whant to crate a makefile for compile app for this terminal.
I have "VRXSDK" version 1.2.0
howto do it?
or how to compile a file like "main.c" or "main.cpp" till have a execute file for verifone POS terminal
Wherever you got your "VRXSDK" from, you should also be able to get some sample project files. You will find a make file in there (likely with a .smk extension). I would recommend you start with that and as you read through it, that should give you more specific questions to ask and things you can look up using your favorite search engine.
A make file is, in essence, a program that invokes the compiler with input parameters you determine based on various factors. It will also invoke the linker to tie it all together. How you go about this varies wildly from one implementation to another, so "How do I create a make file" is just about as broad as "how do I write a program?" which makes answering it here rather challenging. However, to get you started...
I use Visual Studio as my IDE and I am using NMake. I actually have 2 layers of make files. The outer layer is what is called when I say "build" from my IDE and it is very short:
# Pick one of the following (for LOG_PRINTF messages)
#CompileWithLogSys = -DLOGSYS_FLAG
CompileWithLogSys =
all:
$(MAKE) /i /f coreBuild.smk /a TerminalType=$(Configuration) CompileWithLogSys=$(CompileWithLogSys) VMACMode=Multi
$(MAKE) /i /f coreBuild.smk /a TerminalType=$(Configuration) CompileWithLogSys=$(CompileWithLogSys) VMACMode=Single
Lines starting with # are comments.
This outer file makes it really easy for me to toggle a few things when I want to build different variations. You can see that I have turned OFF compliation with LogSys. The more important thing the 2-layer approach gives me is an easy way to compile 2 different versions with a single command to build. This runs nmake with "VMACMode" set to "Multi" and then runs it again with it set to "Single". The inner make file will see that parameter and compile to a different root folder for each so in the end I wind up with 2 folders, each with a different version.
You can do a web search on "nmake parameters" to see what things like /i and /f do, as well as other options I'm not using here. However, I would like to direct your attention to TerminalType=$(Configuration). In Visual Studio, you can select from a dropbox if you want "Debug" or "Release". Those 2 options are the default options, but you can change them; in my case, I have modified them to "eVo" and "Vx". Now I just select in my drop down box which version I want to compile for and that gets passed in. Alternately, I could just hard code both into my outer make file. That's just preference.
My inner make file (which is named "coreBuild.smk") gets much more interesting.
Generally, you start by defining variables, such as "include paths":
# Includes
SDKIncludes = -I$(EVOSDK)\include
ACTIncludes = -I$(EVOACT)include
VCSIncludes = -I$(EVOVCS)include
EOSIncludes = -I$(EOSSDK)\include\ssl2
And/Or libraries:
#Libraries
ACTLibraries = $(EVOACT)OutPut\RV\Files\Static\Release
#Others you may want to include, but I am not using:
#LOGSYSLibraries = $(EVOVMAC)\Output\RV\Lib\Files\Debug
#EOSLibraries = $(EOSSDK)\lib
As well as the path(s) to your files
# App Paths
AppIncludes = .\include
SrcDir = .\source
ObjDir = .\obj
OutDir = .\Output\$(TerminalType)\$(VMACMode)\Files
ResDir = .\Resource
I also like to define my project name here:
ProjectName = MakeFileTest
Note that OutDir uses the TerminalType and VMACMode that we passed in in order to go to a unique folder.
Next, you would generally set your compiler options
# Compiler Options
# Switch based on terminal type
!IF "$(TerminalType)"=="eVo"
CompilerCompatibility=-p
DefineTerminalType = -DEVO_TERMINAL
!ELSE
CompilerCompatibility=
DefineTerminalType = -DVX_TERMINAL
!ENDIF
# Switch based on Multi or Single mode (VMACMode)
!if "$(VMACMode)"=="Multi"
VMACIncludes = -I$(EVOVMAC)include
DefineMulti = -DMULTI_APP_ENABLED
!else
VMACIncludes =
DefineMulti =
!endif
An interesting thing to note above is the -DMULTI_APP_ENABLED. The program I wrote has some blocks that are dependent on #ifdef MULTI_APP_ENABLED. This is not any special name--it's just one I came up with, but the compiler will define it right before it starts compiling my code, so I can turn those code blocks on and off right here.
Next, we are going to kinda' gather everything together. We will start by defining a new var, "Includes" and it will have the flag "-I" (to indicate "include" and then all the things we said above that we wanted to include:
Includes = -I$(AppIncludes) $(SDKIncludes) $(ACTIncludes) $(VMACIncludes) $(VCSIncludes)
Note that you could just type everything long hand here and not go through the extra steps of defining the vars in the first place, but it makes it easier to read, so I think this is pretty normal.
We do pretty much the same thing with compiler options, although note that the specific flags (ex, "-D" "-p") were already included in the original var declarations, so we leave them out here:
COptions =$(CompilerCompatibility) $(CompileWithLogSys) $(DefineTerminalType) $(DefineMulti) -DDEV_TOGGLES_FOR_SYNTAX
Next we set a variable that will tell the linker where the object files are that it needs to stitch together. Note that if you insert new lines, as I have, you need the '\' to tell it that it continues on the next line
# Dependencies
AppObjects = \
$(ObjDir)\$(ProjectName).o \
$(ObjDir)\Base.o \
$(ObjDir)\printer.o \
$(ObjDir)\UI.o \
$(ObjDir)\Comm.o
We will also set one for any libaries we want to link in:
Libs = $(ACTLibraries)\act2000.a
OK, next we have to sign the file(s). We are trying to tell nMake that we also will be creating the resource file and compiling the actual code.
If we are doing a multi-app build, then pseudoOut depends on the .res and the .out files. If not, then it just depends on the .out, because there is no .res. If the the dependent file(s) has/have changed more recently than pseudoOut, then run commands vrxhdr..., filesignature..., and move... NOTE that the indentations seen below are required for nMake to work properly.
!if "$(VMACMode)"=="Multi"
pseudoOut : $(ResDir)\$(ProjectName).res $(OutDir)\$(ProjectName).out
!else
pseudoOut : $(OutDir)\$(ProjectName).out
!endif
# This calls vrxhdr: the utility program that fixes the executable program’s header required to load and run the program. Vrxhdr is needed when you want to move a shared library around on the terminal.
$(EVOSDK)\bin\vrxhdr -s 15000 -h 5000 $(OutDir)\$(ProjectName).out
# do the signing using the file signature tool and the .fst file associated with this TerminalType.
"$(VSFSTOOL)\filesignature" $(TerminalType)$(VMACMode).fst -nogui
#echo __________________ move files to out directory __________________
# rename the .p7s file we just created
move $(OutDir)\$(ProjectName).out.p7s $(OutDir)\$(ProjectName).p7s
!if "$(VMACMode)"=="Multi"
copy $(ResDir)\imm.ini $(OutDir)\imm.ini
copy $(ResDir)\$(ProjectName).INS $(OutDir)\$(ProjectName).INS
copy $(ResDir)\$(ProjectName).res $(OutDir)\$(ProjectName).res
!endif
#echo *****************************************************************
Note that the "echo" commands are just to help me read my output logs, as needed.
OK, now we link.
"WAIT!" I can hear you saying, "We haven't compiled yet, we already issued a command to sign, and now we are linking? This is totally out of order!" Yes and no. We haven't actually issued the command to sign yet, we have merely told nmake that we may want to do that and how to do it if we decide so to do. Similarly, we aren't issuing the command to link yet, we are just telling nmake how to do it when we are ready.
# Link object files
$(OutDir)\$(ProjectName).out : $(AppObjects)
$(EVOSDK)\bin\vrxcc $(COptions) $(AppObjects) $(Libs) -o $(OutDir)\$(ProjectName).out
Remember that mutli-app programs need a .res file. Single apps don't. The following will actually build the .res file, as needed.
!if "$(VMACMode)"=="Multi"
# compile resource file
$(ResDir)\$(ProjectName).res : $(ResDir)\$(ProjectName).rck
$(EVOTOOLS)rck2 -S$(ResDir)\$(ProjectName) -O$(ResDir)\$(ProjectName) -M
!endif
Remember those AppObjects? We are finally ready to make them. I'm using the following flags
-c = compile only
-o = output file name
-e"-" => -e redirect error output from sub-tools to... "-" to stdout. (These are all then redirected via pipe | )
Again, wherever you got your VRXSDK, you should also be able to get some documentation from VeriFone. See "Verix_eVo_volume 3", page 59 for more details on the flags
$(ObjDir)\$(ProjectName).o : $(SrcDir)\$(ProjectName).c
!IF !EXISTS($(OutDir))
!mkdir $(OutDir)
!ENDIF
-$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\$(ProjectName).o $(SrcDir)\$(ProjectName).c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\Base.o : $(SrcDir)\Base.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\base.o $(SrcDir)\Base.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\myprinter.o : $(SrcDir)\printer.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\printer.o $(SrcDir)\printer.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\UI.o : $(SrcDir)\UI.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\UI.o $(SrcDir)\UI.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\Comm.o : $(SrcDir)\Comm.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\Comm.o $(SrcDir)\Comm.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"

How to see exactly what make is doing

Ive got some large make files for a third party project that are not building due to linker issues.
From looking at the make files, I think it should be executing something like:
LIBS = -lm
CC = gcc
bin = bin
myapp: $(bin)/main.o $(bin)/other.o $(bin)/etc.o
$(CC) $(bin)/main.o $(bin)/other.o $(bin)/etc.o $(LIBS) -o myapp
gcc bin/main.o bin/other.o bin/etc.o -lm -o myapp
Instead from the error it seems to be failing on something like: It also didn't put any of the .o files in the expected bin/ location, but just left them in the source directory...
cc main.o -o myapp
But I cant locate anywhere that might come from. Is there some way to get some kind of stacktrace through the make files?
I am aware of -n and -d, but neither seems to tell me what target line and file yeilded that command, or which series of targets led there and the values of any $() expansions (The one im expecting is the only myapp: I can find in any of the makefiles...)
Check out the --debug option. From my manpage:
--debug[=FLAGS]
Print debugging information in addition to normal processing. If the
FLAGS are omitted, then the behavior is the same as if -d was specified.
FLAGS may be a for all debugging output (same as using -d), b for basic
debugging, v for more verbose basic debugging, i for showing implicit
rules, j for details on invocation of commands, and m for debugging
while remaking makefiles.
remake is a very good choice but in a pinch something like the following (saved as debug.mk) can be a good help too. It won't tell you as much as remake but it might tell you enough to start with.
# Use as: MAKEFILES=debug.mk make
OLD_SHELL := $(SHELL)
ifneq (undefined,$(origin X))
override X = -x
endif
SHELL = $(if $#,$(warning Running $#$(if $<, (from: $<))$(if $?, (newer: $?))))$(OLD_SHELL) $(X)
You can print out the other automatic variables there too if you wanted to see a bit more about what was going on.

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.

"Illegal instruction" on basic assembly program - not even hello world - why is linking needed?

I just figured this out but instead of splitting my new question ("why?") into another question I think its best if the solution to this problem and an explanation were to be kept on the same page.
I'm writing a basic assembly program to just start and immediately quit using the kernel interrupt at int 0x80. My current code is simply as follows:
/* Simple exit via kern-interrupt */
.globl start
start:
pushl $0x0
movl $0x1, %eax
subl $4, %esp
int $0x80
assembled with
as -arch i386 <file>.s
upon executing I get a one-line error:
Illegal instruction
It's bizzare, even commenting everything out still results in Illegal instruction despite there being no instructions at all. Am I missing a linking step, despite there being no other files to link to? Yes I am
EDIT: Allow me to rephrase my question, why do you need to link when there is no library or anything to link to?
You do need to link it to create an executable. By default, as just gives you an object file, which is something you can link into an executable (either with other object files or on its own) but is not itself a valid executable. Try:
as -arch i386 -o file.o file.s
ld -o file file.o
In answer to your question:
Why do you need to link when there is no library or anything to link to?
Because the assembler doesn't know that you're not going to link with something else.
Unlike the gcc compiler where it assumes you want a program unless told otherwise (with the -c option), as gives you an object file by default. From the manpage:
"as" is primarily intended to assemble the output of the GNU C compiler "gcc" for use by the linker "ld"
If you want a one-step command, you can create a script such as asld:
as -arch i386 -o $1.o $1.s
ld -o $1 $1.o
and then just use asld file.
Or, you could set up makefiles to do all the heavy lifting for you.
You could make the same argument about a C program, I am not using any libraries why do I have to link.
Because that is how the toolchain was designed. One set of tools takes you from source code (any/many languages) to object files which are most of the time incomplete. The link stage, even if as paxdiablo shows, only takes your object file and makes it an executable, is required. If nothing else your .text address is (usually) needed and that comes from the linker stage.
It makes a lot of sense to do it this way, the link stage is complicated enough as it is, make that one tool that does that job and is good at that job. Do your system engineering and define an interface to that tool. The language tools have a complicated job to do have them just do that job, the output being an object file, which is as far as they can resolve without having to become a linker.
If you wish to not use this toolchain and perhaps use nasm or something like that where you can go directly from assembly to binary in one command line step.

Add linker option to boost build on HPUX

On HPUX I need to use the +h link option to get the boost 1.39.0 shared libraries to contain correct paths.
-Wl,+h$(SPACE)-Wl,$(<[-1]:D=)
(From http://www.nabble.com/HPUX-aCC:-Howto-avoid-building-boost-libraries-containing-absolute-library-path-references-when-calling-bjam-install-td17619511.html)
I've tested that this works by hacking the gcc.jam toolset file:
796c796
< "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)
---
> "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,+h$(SPACE)-Wl,$(<[-1]:D=) -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)
But now I want a permanent solution, and I can't work out how.
First I tried putting a bjam conditional in the actions link.dll section, but that section contains shell commands.
Then I tried adding the extra section to the OPTIONS variable for those targets. But that didn't seem to have any effect on the link.
Finally I tried creating a separate toolset as a copy of gcc.jam (hpuxgcc.jam), but I couldn't get that to work at all. I guess there are more places I need to change variable names, but the Jam syntax is beyond what I understand.
Does anyone have some better idea how to get this to work? Or should I just convert the hacky version into a patch I run before building Boost? Surely there's a better way?
Are guess the question is either:
a) How do I (conditional on the platform) add the text to the linker command in the gcc.jam
Or:
b) How do I create a new toolset based on gcc.jam?
Which ever is easier...
What does -h option do? Does it set the "soname"? If so, note the HAVE_SONAME and SONAME_OPTION use in the same action. Then, note the block of code in gcc.jam where it is set:
if [ os.name ] != NT && [ os.name ] != OSF && [ os.name ] != HPUX && [ os.name ] != AIX
{
# OSF does have an option called -soname but it does not seem to work as
# expected, therefore it has been disabled.
HAVE_SONAME = "" ;
SONAME_OPTION = -h ;
}
You can tweak this according to your platform.
I suggest you follow up with this on boost-boost#lists.boost.org, which is much better place for Boost.Build questions than stack overflow.

Resources