Taking an nmake project, specifically Ruby, and trying to see exactly what commands are used to build it. nmake says what files it is compiling, but not what commandline it is using to compile each file. The closest thing to an obviously relevant option is /D, but that doesn't shed much light on it.
Is there a way, by supplying some option to nmake or otherwise, to see exactly what commands it is issuing?
There is no general way of causing all the commands to be echoed, such as using a command option. However it is possible to build such an option by yourself, but it does involve making global edits to the Makefile. However, with clever use of an editor (such as one that matches regular expressions) you can quickly make the changes and get what you desire.
The technique is described in this Blog article: Writing Portable Makefiles, Section §5.
Every makefile implementation allows a command to be proceeded by an # symbol which causes the echo to be disabled. The technique is to use a macro in place of the # symbol, such as in this example Makefile:
!MESSAGE Makeflags=$(MAKEFLAGS)
!IFNDEF LOG
L=#
!ELSE
! IF [ IF /I $(LOG) == yes ( EXIT 1 ) ELSE ( EXIT 0 ) ] == 0
L=#
!ELSE
L=
!ENDIF
!ENDIF
# To be a valid makefile it must have some rules to perform
all:
$(L)echo;This is a command being executed
This can be demonstrated thus:
C:\Users\Brian>nmake /NOLOGO
Makeflags=L
This is a command being executed
C:\Users\Brian>nmake /NOLOGO LOG=yes
Makeflags=L
echo;This is a command being executed
This is a command being executed
C:\Users\Brian>nmake /NOLOGO LOG=no
Makeflags=L
This is a command being executed
Then, all that remains is to change every # at the beginning of a command to '$(L)' (leaving all the other # symbols unchanged of course!).
I use /N to display the command lines and /A to run all targets (not just out-of-date targets).
> nmake /F example.mak /A /N
Docs: https://msdn.microsoft.com/en-us/library/afyyse50.aspx
Related
Using nmake I have the following makefile which currently does what I need it to do. mycmd (the program being run) will take a .inp file and produce a .out file. I can make as many .inp files as I need to and the makefile doesn't have to change. It will find them all and make all the relevant .out files.
#####################################################################################
# A SUFFIXES declaration is required in order to later use the rule with target .inp.out
#####################################################################################
.SUFFIXES: .inp
#####################################################################################
# Here, NMAKE will expand *.inp in the prereq list for all, into the list of *.inp
# files in the directory, and then it will start a new NMAKE instance, specifying the
# goals to build all those files.
#####################################################################################
all: *.inp
$(MAKE) $(**:.inp=.out)
#####################################################################################
# $(*B) represents the current target's base name minus the path and the file extension
#####################################################################################
.inp.out:
mycmd -i $(*B).inp -o $(*B).out
My question is, how do I enhance this makefile further so that I could, for example, run it for a set of .inp files, so not *.inp but say, ABC*.inp?
A simple modification to your makefile should work. Add a new $(pattern) macro:
.SUFFIXES: .inp
pattern = * # new macro; defaults to *
all: $(pattern).inp # use it!
#$(MAKE) -nologo $(**:.inp=.out)
.inp.out: # dummy stub for testing
#echo mycmd -i $(*B).inp -o $(*B).out
#type NUL > $(*B).out
Then in your command line, overwrite pattern. For example, nmake -nologo pattern=ABC*.
Update: The command line in your makefile:
$(MAKE) $(**:.inp=.out)
will fail with fatal error U1095: expanded command line ... too long if the string $** is too long. On my system, this happens at roughly 32800 characters.
Adding an exclamation mark ! to the start (see here) doesn't seem to work, probably because there is no simple $**. Two workarounds are to use:
!call set a=$** & call nmake %%a:.inp=.out%%
or:
!for %a in ($**) do nmake -nologo %~na.out
These are both about twice as slow as your original, with a do-nothing mycmd stub. (The for loop here is not really a loop, because $** is just a single item.)
A different solution is to keep your original makefile, and use a DOS command such as:
for %a in (ABC*.inp) do nmake -nologo %~na.out
Here the syntax %~na removes the extension from the variable %a.
This is slightly slower than just using the makefile, but not by much. For example, with 600 inp files, and a mycmd stub, on my system this command takes 20 seconds compared to 15 seconds for the makefile.
In the file make.bat found in go/src (after unzipping tar), there is a gcc compile command even before a check for CGO_ENABLED ever is used. This messes up the bootstrap tool build.
For security reasons I cannot install GCC on Windows via cygwin or ming. However, the compiles are for various .c files which makes me unsure about what to do next.
I've tinkered about with the source code and the environment variables, especially CGO_ENABLED, which should have been all I needed. However, the make.bat haas that irritating little c compile that seems to be throwing me off.
This is the make.bat file and the compile that's throwing me off:
:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
:: to include all cgo related files, .c and .go file with "cgo"
:: build directive, in the build. Set it to 0 to ignore them.
#echo off
:: Keep environment variables within this script
:: unless invoked with --no-local.
if x%1==x--no-local goto nolocal
if x%2==x--no-local goto nolocal
setlocal
:nolocal
set GOBUILDFAIL=0
if exist make.bat goto ok
echo Must run make.bat from Go src directory.
goto fail
:ok
:: Clean old generated file that will cause problems in the build.
del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
:: Grab default GOROOT_FINAL and set GOROOT for build.
:: The expression %VAR:\=\\% means to take %VAR%
:: and apply the substitution \ = \\, escaping the
:: backslashes. Then we wrap that in quotes to create
:: a C string.
cd ..
set GOROOT=%CD%
cd src
if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL=%GOROOT%
set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
echo # Building C bootstrap tool.
echo cmd/dist/*.c
if not exist ..\bin\tool mkdir ..\bin\tool
:: Windows has no glob expansion, so spell out cmd/dist/*.c.
gcc -O2 -Wall -Werror -o cmd/dist/dist.exe -Icmd/dist %DEFGOROOT% cmd/dist/buf.c cmd/dist/build.c cmd/dist/buildgc.c cmd/dist/buildgo.c cmd/dist/buildruntime.c cmd/dist/main.c cmd/dist/windows.c cmd/dist/arm.c
if errorlevel 1 goto fail
.\cmd\dist\dist env -wp >env.bat
if errorlevel 1 goto fail
call env.bat
del env.bat
echo.
The final result is just a standard gcc error :
Building C bootstrap tool.
cmd/dist/*.c
"gcc" is not recognized as...
Go 1.4 is written in C, and therefore needs C to be compiled. CGO is completely unrelated to this.
Go 1.5 was the first version not to require C to be built.
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"
What does the prefix #- mean in a makefile? Any difference from using # without -? For example, in the following case:
ifndef NO_CBLAS
#echo Generating cblas.h in $(DESTDIR)$(OPENBLAS_INCLUDE_DIR)
#sed 's/common/openblas_config/g' cblas.h > $(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/cblas.h
endif
ifndef NO_LAPACKE
#echo Copying LAPACKE header files to $(DESTDIR)$(OPENBLAS_LIBRARY_DIR)
#-install -pDm644 $(NETLIB_LAPACK_DIR)/lapacke/include/lapacke.h $(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/lapacke.h
#-install -pDm644 $(NETLIB_LAPACK_DIR)/lapacke/include/lapacke_config.h $(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/lapacke_config.h
#-install -pDm644 $(NETLIB_LAPACK_DIR)/lapacke/include/lapacke_mangling_with_flags.h $(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/lapacke_mangling.h
#-install -pDm644 $(NETLIB_LAPACK_DIR)/lapacke/include/lapacke_utils.h $(DESTDIR)$(OPENBLAS_INCLUDE_DIR)/lapacke_utils.h
endif
ifndef NO_STATIC
#echo Copying the static library to $(DESTDIR)$(OPENBLAS_LIBRARY_DIR)
#install -pm644 $(LIBNAME) $(DESTDIR)$(OPENBLAS_LIBRARY_DIR)
#cd $(DESTDIR)$(OPENBLAS_LIBRARY_DIR) ; \
ln -fs $(LIBNAME) $(LIBPREFIX).$(LIBSUFFIX)
endif
Section 5 Writing Recipes in Rules of the GNU make Manual has information about both of these things in it. Specifically section 5.2 and 5.5.
5.2 Recipe Echoing
Normally make prints each line of the recipe before it is executed. We call this echoing because it gives the appearance that you are typing the lines yourself.
When a line starts with ‘#’, the echoing of that line is suppressed. The ‘#’ is discarded before the line is passed to the shell. Typically you would use this for a command whose only effect is to print something, such as an echo command to indicate progress through the makefile:
and
5.5 Errors in Recipes
After each shell invocation returns, make looks at its exit status. If the shell completed successfully (the exit status is zero), the next line in the recipe is executed in a new shell; after the last line is finished, the rule is finished.
If there is an error (the exit status is nonzero), make gives up on the current rule, and perhaps on all rules.
Sometimes the failure of a certain recipe line does not indicate a problem. For example, you may use the mkdir command to ensure that a directory exists. If the directory already exists, mkdir will report an error, but you probably want make to continue regardless.
To ignore errors in a recipe line, write a ‘-’ at the beginning of the line’s text (after the initial tab). The ‘-’ is discarded before the line is passed to the shell for execution.
With make on linux, we can do things like:
foo=$(shell /bin/bar)
which runs the command bar and assigns the output to foo. This can later be used in the makefile by referencing $(foo).
But now I have a Microsoft project on my hands that is compiled and linked with the Microsoft nmake.exe. Is there an equivalent thing for nmake that would allow me to run a command and assign the output to a variable?
Although this is an old question, there is a method of doing what is asked; its just convoluted, like everything in batch files!
One has to use the combined mechanisms of the fact that make imports environmental variables and that the preprocessor can invoke commands, and then call the Makefile recursively. It assume the Makefile is called Makefile (with no extension, which is the default).
!IFNDEF MAKE
MAKE=NMAKE
!ENDIF
!IFNDEF SHELLVALUE
! IF [echo off && FOR /F "usebackq" %i IN (`hostname`) DO SET SHELLVALUE=%i && $(MAKE) /$(MAKEFLAGS) /nologo /f $(MAKEDIR)\Makefile && exit /b ] == 0
! MESSAGE Make completed
! ELSE
! ERROR Error in nmake
! ENDIF
!ELSE
# $(SHELLVALUE) now contains the string returned from the command USERNAME
!MESSAGE Shellvalue is $(SHELLVALUE)
# Put the parts of the makefile that depend on SHELLVALUE here
!ENDIF
#
# To be a valid makefile it must have some rules to perform
all:
#echo;$(SHELLVALUE)
Yes, I know its horrible, but it does demonstrate how to do the technique, which can be done with any shell command and not just hostname.
I think the answer is "no." There is no equivalent.
I'd recommend that you convert to MSBuild if possible.