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.
Related
Remark: Put this Question on tex.stackexchange and was adviced to also ask here
Under Windows (using make from GnuWin32) i want to set my TEXINPUTS variable in a makefile
My Structure is as follows:
./
|-texmf_project/
|-Package.sty
|-main.tex
|-makefile
I want to be able to use Package.sty in my compilation process. The files look like this:
Package.sty contains:
\ProvidesClass{Package}[]
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{xcolor}
\newcommand{\red}[1]{\textcolor{red}{#1}}
main.tex contains:
\documentclass[11pt,a4paper]{report}
\usepackage{xcolor}
\usepackage{Package}
\begin{document}
Hello World\\
\red{Hello World}
\end{document}
Now i want to set the TEXINPUTS to include what is in ./texmf-project/
Hence my Makefile:
edit:
set TEXINPUTS=./texmf-project//;
pdflatex -synctex=1 -interaction=nonstopmode main.tex
del *.log
del *.aux
However this does not seem to make the location available for compilation.
However if I put the line
set TEXINPUTS=./texmf-project//; directly into the cmd and run make afterwards it works.
I believe I am making a mistake with the set, but I am far from beeing an expert.
Any helps or hints would be greatly appreciated.
Edit: Fixed a spelling mistake
Please remember that every recipe line is executed in a separate shell, so your set is executed in a different shell than pdflatex. Either put those two commands on a single line, or concatenate lines with \ so that lines are executed in a single shell, i.e.:
edit:
set TEXINPUTS=./texmf-project//; \
pdflatex -synctex=1 -interaction=nonstopmode main.tex
Edit:
Since this is Windows, it gets more complicated. Just adding \ and even & is not enough, since make will run it in a single line (through a batch file):
> type Makefile
all:
set TEXINPUTS=./texmf-project// & \
echo %TEXINPUTS%
> make -dr
...
Must remake target 'all'.
Creating temporary batch file C:\Users\user\AppData\Local\Temp\make11444-1.bat
Batch file contents:
#echo off
set TEXINPUTS=./texmf-project// & echo %TEXINPUTS%
...
ECHO is off.
...
Now, cmd.exe uses a line parser that expands variables when the line is parsed, so it first expands %TEXINPUTS% to an empty string (since it was not yet defined) and after that it evaluates the code which sets the variable. Therefore it is crucial that those commands are on separate lines to have variable set before it is used. The easiest way (if you use quite modern make) is including a .ONESHELL directive which would place all recipe into the batch and execute all at once:
> type Makefile
.ONESHELL:
all:
set TEXINPUTS=./texmf-project//
echo %TEXINPUTS%
> make -dr
...
Must remake target 'all'.
Creating temporary batch file C:\Users\user\AppData\Local\Temp\make29908-1.bat
Batch file contents:
#echo off
set TEXINPUTS=./texmf-project//
echo %TEXINPUTS%
...
./texmf-project//
...
Alternatively, if you don't somehow calculate the value, you can just set the variable at the make level (global or target level) and export it to the process, i.e.:
> type Makefile
all: export TEXINPUTS := ./texmf-project//
all:
echo %TEXINPUTS%
> make -dr
...
Must remake target 'all'.
Creating temporary batch file C:\Users\user\AppData\Local\Temp\make25392-1.bat
Batch file contents:
#echo off
echo %TEXINPUTS%
...
./texmf-project//
...
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.
I am trying to remove the path prefix. Here is a small example showing just the issue.
Makefile
dist_directory = ./dist
default: build
build: $(patsubst %.md, $(dist_directory)/%.html, $(wildcard *.md))
$(dist_directory)/%.html: %.md
#echo start
#echo $#
#echo ${$#//$(dist_directory)/}
#echo end
Create a file: touch stuff.md
Then build: make
The output is:
start
dist/stuff.html
end
The expected output is:
start
dist/stuff.html
/stuff.html
end
There are similar posts on Stack Exchange. However, they have not worked for me in a Makefile for some reason. I'm probably doing something wrong.
https://unix.stackexchange.com/questions/311758/remove-specific-word-in-variable
Remove a fixed prefix/suffix from a string in Bash
Remove substring matching pattern both in the beginning and the end of the variable
You have many issues here. The most fundamental one is that if you want to use shell variables you have to escape the dollar sign so that make doesn't interpret it. And, you can only use shell variable substitutions on shell variables, while $# is a make variable, so you need:
#foo='$#' ; echo $${foo//$(dist_directory)/}
The more subtle one is that make always uses /bin/sh (POSIX standard shell) when it invokes recipes, and the above syntax is specific to bash. One way around that would be to explicitly set SHELL := /bin/bash in your makefile to force make to use bash. Luckily that is not necessary because POSIX sh can also do this, as mentioned by Reda in another answer:
#foo='$#' ; echo $${###*/}
But even more, you don't need any of this because make sets the automatic variable $* to the part of the target that matches the stem (the %):
#echo $*.html
It also sets $(#F) to the filename part of the $# variable:
#echo $(#F)
ETA
If you want to do something very similar to your shell variable expansion using GNU make you can use:
#echo $(patsubst $(dist_directory)/%,%,$#)
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
I'm working on a project with the Dialogic DivaSDK to be able to analyze telephone calls. Since the DivaSDK supports Java via JNI, I wanted to give the samples a try. Unfortunately: the whole Java documentation is not as complete as the C# one is. So it seems to be like fishing in murky waters.
In my first step I wanted to look into the sample ( Link to DivaSDK with Sample Files )files and try them out. Each sample has a makefile which has to be run. The only part within the manual which scratches my problem sounds like this:
For details how to compile and link your application please have a look at any of the samples provided with the Diva SDK. In every sample subdirectory you will find a makefile, that describes the compilation and link process of that application. The evaluation of the makefile requires some knowledge of shell scripting and makefile syntax and is beyond the scope of this document.
My problem right now is that the given makefile doesn't work the way it is supposed to be. I get the error "No Targets" Since I have not that much knowledge of makefiles, I can't figure out what is wrong with that file.
#-------------------------------------------------------------------------------
#
# makefile to geenrate the Diva SDK Java sample "SimpleApp". This makefile
# generate the class files for teh framework and the sample and creates
# a SimpleApp.jar that can be executed via jav -jar SimpleApp
#
# The makefile assumes that the java development enmvironment is installed and
# the java tools are accessable from the command prompt.
#
#-------------------------------------------------------------------------------
FRAMEWORK_PATH=..\..\Framework
FRAMEWORK=$(FRAMEWORK_PATH)\DivaAPI.java $(FRAMEWORK_PATH)\DivaCallBase.java
BIN_DIR=.\bin
SRC_DIR=.\src
TRAGET=SimpleApp
#edited with hint from #Aaron Digulla
all : $(BIN_DIR)\$(TRAGET).jar
SRC=$(SRC_DIR)\SimpleApp.java \
$(SRC_DIR)\AppCall.java
$(BIN_DIR)\$(TRAGET).jar: $(SRC)
#echo #-----------------------------------------------
#echo # Generate class files
#echo #-----------------------------------------------
javac -d $(BIN_DIR) -sourcepath $(FRAMEWORK_PATH) $(FRAMEWORK) $(SRC)
#echo #-----------------------------------------------
#echo # Generate jar files and clean class and manifest
#echo #-----------------------------------------------
copy $(SRC_DIR)\manifest.txt $(BIN_DIR)
cd $(BIN_DIR)
jar -cvfm $(TRAGET).jar manifest.txt *.class > nul
del *.class
del manifest.txt
cd ..
#echo #-----------------------------------------------
#echo # $(BIN_DIR)\$(TARGET).jar successfully created
#echo #-----------------------------------------------
It seems, that the target definition is wrong, but I don't know in which way. Any tips would be very much appreciated.
edit1: With the hint from #Aaron Digulla it works a little bit better. At least the target is recognized. But now there is an error which tells me, that there are no rules to create the jar.
edit2: Well... It seems that the filepaths are wrong. If I replace some of the backslashes ( "\" ) with normal slashes ( "/" ), the compiling starts. It stops at copy though...
The error means there is no target all in the Makefile and make cowardly refuses to continue.
My guess is that this Makefile is supposed to be called from another Makefile.
Add this line to the Makefile:
all : $(BIN_DIR)\$(TRAGET).jar
and it should work. If the error persist, make sure you use GNU make or try make all