GNU make: include file only if target is not "clean" - gnu-make

Using GNU make, I want to include a file, except if the current target is "clean".
That is, I want to do the equivalent of the following:
ifneq($(TARGET),clean)
-include somefile.txt
endif
But for that, I need a variable whose value is the target given on the command line (here named $(TARGET)). Such a variable does not seem to exist, and I can understand why, because you could have multiple targets on the command line, some of which you might want to include the file for, and others not. Actually, it would be fine if the file is included when there are other targets besides "clean". The only real problem I currently have is that when the file to be included does not exist, Make will try to build it, which is unnecessary when you're about to delete it again when executing the "clean" target.
So, is there another way to accomplish what I want?

You can use MAKECMDGOALS. Use it like this to handle multiple arguments on the command line:
ifeq (clean,$(filter clean,$(MAKECMDGOALS)))
-include somefile.txt
endif
However, this is often fraught because if you run make clean all or whatever, the include file won't be included even though it might be needed for all.
If you really need this to be reliable another way is to use recursion for your "top-level" arguments, running them one at a time in a sub-make.

You could usefully check that if clean is a target then it is the only target. Otherwise strange things can go wrong silently causing much wailing and gnashing of teeth. My most recent Makefile includes the following. (NB tested but not as yet used extensively).
ifeq (clean,$(filter clean,$(MAKECMDGOALS)))
ifneq($(strip $(filter-out clean,$(MAKECMDGOALS)))
$(error ERROR: can not make other targets with clean
endif
endif

Related

Why does gnu make delete this file?

Consider this Makefile:
.PHONY: all
all: main.txt
main.txt: build/main.txt
cp build/main.txt .
%/main.txt: %/data.txt
cp $*/data.txt $*/main.txt
%/data.txt:
touch $*/data.txt
After running make, build/data.txt is removed automatically. Why is this the case?
I tried adding .PRECIOUS: build/% to the file, but it it not help, the file was still removed. How can I prevent this?
According to the GNU Make documentation
You can also list the target pattern of an implicit rule (such as ‘%.o’) as a prerequisite file of the special target .PRECIOUS to preserve intermediate files created by rules whose target patterns match that file’s name.
the prerequisite for.PRECIOUS needs to be the (exact) target pattern of an existing implicit rule.
In your case this would be %/data.txt instead.
The documentation hints at this, but is not particularly clear about it.
As a side note: As far as I can tell build/main.txt is not automatically deleted since it is explicitly named as a prerequisite for the main.txt target and build/data.txt is automatically deleted since it is never explicitly named.

Fail a grunt build when debug prints exist in source

I am working on a PHP/Javascript project where I've nicely set up a build workflow. It involves testing, minifying, compressing into the final zip deliverable, and a whole lot of other nice stuff.
I want to build a task that fails when there are certain patterns in the source code. I would like to look for any print_r(), error_log(), var_dump(), etc functions, and halt the build process if there are any. Perhaps later I would like to check for things in Javascript or CSS so this is not only a PHP question.
I know it can be done with grunt-shell and grep but I'd like to know the following:
Are there any grunt plugins specific to this task? Ideally I would like to be able to specify a list of regexes per file type, and to set whether to continue or fail the build on pattern match.
How do others tackle the problem of double-checking the packaged source for the most common debug statements or other patterns?
Not a complete answer to my question, but I've recently come across this grunt plugin which is somewhat related. It removes console.log statements from JavaScript. Haven't tried it yet. Looks good. I still would like to know if there's something similar for PHP though.
http://grunt-tasks.com/grunt-remove-logging-calls/
Edit: Seeing as there's only tumbleweeds rolling in the wind here, I'm posting my workaround that's based on grunt-shell. However this is not what I was looking for. It's not perfect because it doesn't do proper syntax parsing:
shell: {
check_debug_prints: {
command: '(! (egrep -r "var_dump|print_r|error_log" --include=*.php src || egrep -r "console\.\w+|debugger;" --include=*.js src) ) || (echo "Debug prints in source - build aborted" && false )'
}
},
and
grunt.loadNpmTasks( 'grunt-shell' );
Edit 2: I finally found the exact grunt plugin I was looking for. It is grunt-search. There is a failOnMatch boolean option that lets you indicate if a particular regex pattern should cause the build to fail when found.

Qt internationalization and CMake: how to update *.ts and don't lose them

I'm having this CMakeLists.txt in directory with translation files (*.ts):
SET(TRANSLATIONS
lang_de.ts
lang_en.ts
)
FIND_PACKAGE(Qt5LinguistTools)
QT5_ADD_TRANSLATION(QM_FILES ${TRANSLATIONS})
SET(QM_FILES ${QM_FILES} PARENT_SCOPE)
ADD_CUSTOM_TARGET (translations ALL DEPENDS ${QM_FILES})
It builds *.qm files from specified *.ts.
But I want to improve this and get two custom targets, which won't built automatically.
One for appending new strings from sources into ts files, and one for refreshing ts. The last one would update ts from sources and remove obsolete strings from ts.
I've tried to add this after lines above:
ADD_CUSTOM_TARGET (
ts_append
COMMAND QT5_CREATE_TRANSLATION(QM_FILES ${CMAKE_SOURCE_DIR}/src/app ${TRANSLATIONS} OPTIONS -I ${CMAKE_SOURCE_DIR}/src)
)
ADD_CUSTOM_TARGET (
ts_refresh
COMMAND QT5_CREATE_TRANSLATION(QM_FILES ${CMAKE_SOURCE_DIR}/src/app ${TRANSLATIONS} OPTIONS -no-obsolete -I ${CMAKE_SOURCE_DIR}/src)
)
but it seems I can't use QT5_CREATE_TRANSLATION macro inside custom target, isn't it?
Maybe I'm on wrong way, how would you solve this problem: easy updating of ts and don't lose them after make clean?
To solve the make clean problem, add a sub directory (ADD_SUBDIRECTORY(translations)) and add SET_DIRECTORY_PROPERTIES(PROPERTIES CLEAN_NO_CUSTOM 1) to the contained CMakeLists.txt.
See here for an example of that.
For the second part of your question there are two possible ways to do it. Either use FILE(WRITE <filename> "QT5_CREATE_TRANSLATION(QM_FILES ${SOURCE_DIR}/src/app ${TRANSLATIONS} OPTIONS -I ${SOURCE_DIR}/src)") and then use COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -DTRANSLATIONS=${TRANSLATIONS} <filename> in add_custom_target. I doubt there's a good way of retrieving the contents of QM_FILES though.
The second option is creating two additional sub directories, each with a QT5_CREATE_TRANSLATIONS and a ADD_CUSTOM_TARGET call.

make does not realize that a relative path name dependency is the same as an absolute pathname target

The following is a simplified makefile for a problem I'm having:
all: /tmp/makey/../filey
#echo All done
/tmp/filey:
#echo Filey
When I run make it says:
make-3.79.1-p7: * No rule to make target /tmp/makey/../filey', needed byall'. Stop.
Clearly it does not realize that /tmp/makey/../filey is the same as /tmp/filey. Any ideas how I can make this work?
Thanks
Ciao
-- Murali
Newer versions of GNU make have $(abspath ...) and $(realpath ...) functions you can apply to your prerequisites and targets to resolve the paths to the same string. If you've constructed these names yourself (for example, $(PREFIX)/../filey) then you can use $(dir $(PREFIX))filey instead.
Other than that, there's no way to solve this problem. Make uses string matching on targets and if the strings are not identical, they don't match (there's a special case to ignore the simple prefix ./) Even if make understood this distinction (by applying abspath itself to each target name, maybe) it would still not help in the face of symbolic links for example.
The only "real" answer would be for make to understand something about the underlying file system (device IDs and inodes for example) that let you talk about files without referring to their pathname. However, in a portable program like make doing this is problematic.

zsh: using "less -R" as READNULLCMD

Now, I'm pretty sure of the limitation here. But let's step back.
The simple statement
READNULLCMD="less -R"
doesn't work, generating the following error:
$ <basic.tex
zsh: command not found: less -R
OK. Pretty sure this is because, by default, zsh doesn't split string variables at every space. Wherever zsh is using this variable, it's using $READNULLCMD where it should be using ${=READNULLCMD}, to ensure the option argument is properly separated from the command by a normal space. See this discussion from way back in 1996(!):
http://www.zsh.org/mla/users/1996/msg00299.html
So, what's the best way around this, without setting SH_WORD_SPLIT (which I don't want 99% of the time)?
So far, my best idea is assigning READNULLCMD to a simple zsh script which just calls "less -R" on STDIN. e.g.
#!/opt/local/bin/zsh
less -R /dev/stdin
Unfortunately this seems to be a non-starter as less used in this fashion for some reason misses the first few lines on input from /dev/stdin.
Anybody have any better ideas?
The problem is not that less doesn't read its environment variables (LESS or LESSOPEN). The problem is that the READNULLCMD is not invoked as you might think.
<foo
does not translate into
less $LESS foo
but rather to something like
cat foo | less $LESS
or, perhaps
cat foo $LESSOPEN | less $LESS
I guess that you (like me) want to use -R to obtain syntax coloring (by using src-hilite-lesspipe.sh in LESSOPEN, which in turn uses the "source-highlight" utility). The problem with the latter two styles of invocation is that src-hilite-lesspipe.sh (embedded in $LESSOPEN) will not receive a filename, and hence it will not be able to deduce the file type (via the --infer-lang option to "source-highligt"). Without a filename suffix, "source-highlight" will revert to "no highlighting".
You can obtain syntax coloring in READNULLCMD, but in a rather useless way. This by specifying the language explicitly via the --lang-def option. However, you'll have as little clue as "source-higlight", since the there's no file name when the data is passed anonymously through the pipe. Maybe there's a way to do a on-the-fly heuristic parser and deduce it by contents, but then you've for sure left this little exercise.
export LESS=… may be a good solution exclusively for less and if you want such behavior the default in all cases, but if you want more generic one then you can use functions:
function _-readnullcmd()
{
less -R
}
READNULLCMD=_-readnullcmd
(_- or readnullcmd have no special meaning just the former never appears in any distributed zsh script and the latter indicates the purpose of the function).
Set the $LESS env var to the options you always want to have in less.
So don't touch READNULLCMD and use export LESS="R" (and other options you want) in your zshrc.

Resources