I'm currently trying to compile all my themes in one go, but I can't seem to get it to work.
E.g.:
THEMES := theme_a theme_b theme_c theme_d
build_themes:
$(foreach THEME, $(THEMES), sass web/themes/$(THEME)/scss/style.scss web/themes/$(THEME)/css/style.css)
But it just compiles the first theme and not all.
Is there something wrong with my iteration?
EDIT
After the suggestion by Renaud Pacalet:
RUBY =$(whereis ruby)
SASSC = $(RUBY) sass --style compressed
THEMES := theme_a theme_b theme_c theme_d
SASSDIR = build/scss
CSSDIR = web/themes/custom-themes
SASS := $(wildcard $(SASSDIR)/style_*.scss)
CSS := $(patsubst $(SASSDIR)/style_%.scss, $(CSSDIR)/%/css/style.css, $(SASS))
all: $(CSS)
$(CSSDIR)/%/css/style.css: $(SASSDIR)/style_%.scss
$(SASSC) $< $#
But I still can't seem to get it to work
Make is not yet another scripting language. It is a dependency management utility with building capability. Tell it how to compile any theme:
web/themes/%/css/style.css: web/themes/%/scss/style.scss
sass $< $#
Note that the recipe line (sass $# $<) starts with a tab, not spaces.
This is a pattern rule. $< and $# are two automatic variables that make will substitute respectively by the first prerequisite of the rule and by its target.
This rule means that any CCS named web/themes/<something>/css/style.css depends on the (only) prerequisite web/themes/<something>/scss/style.scss. If make is told to build a CSS, it will search for the corresponding SCSS. If it does not find the SCSS, it will raise an error. If it finds it, it will compare the last modification dates of the CSS and SCSS. If the CSS is newer than the SCSS, make will consider that the CSS is up-to-date and it will not do anything. Else it will consider that the CSS is outdated and it will expand the recipe (by substituting $# and $<) and pass it to the shell.
Next, tell make that you want all your themes to be compiled:
THEMES := theme_a theme_b theme_c theme_d
CSS := $(patsubst %,web/themes/%/css/style.css,$(THEMES))
all: $(CSS)
And that's it. Just invoke make all to get the work done.
The most important thing to remember here is that, thanks to this structure:
target: prerequisite
recipe
make will do much better than a naive script loop: it will re-compile a theme only if the CSS is missing or older than the corresponding SCSS. If invoked with the -j8 option (make -j8 all) it will even parallelize the work by launching up to 8 jobs in parallel.
Bonus: make can also find all your SCSS and compute the list of all buildable CSS:
DIR := web/themes
SCSS := $(wildcard $(DIR)/*/scss/style.scss)
CSS := $(patsubst $(DIR)/%/scss/style.scss,$(DIR)/%/css/style.css,$(SCSS))
all: $(CSS)
$(DIR)/%/css/style.css: $(DIR)/%/scss/style.scss
sass $< $#
Related
Goal of my Makefile is to create in the end a static library *.a out of Fortran77 files and some *.c's + *.h's whereas a specific part of the headers have to be precompiled with a special company internal precompiler which is provided via executable and all you have to hand over is the pathname+filename.
Let's call the Precompiler CPreComp.
The files needing the precompilation *_l.h .
So I want first to collect all the headers I need to precompile and then hand it over to a script which does some magic (env variables blubb blubb) and calls the precompiler.
Here you go with my Makefile:
SHELL=/usr/bin/bash
.SHELLFLAGS:= -ec
SOURCE_PATH = ./src
CPRECOMP = ./tools/cprecomp.exe
DO_CPreComp = $(SOURCE_PATH)/do_cprec
HDREXT = .h
PREC_HEADERS = $(foreach d, $(SOURCE_PATH), $(wildcard $(addprefix $(d)/*, $(HDREXT))))
.PHONY: all prereq
all:: \
prereq \
lib.a
prereq: chmod 777 $(DO_CPreComp)
echo $(PREC_HEADERS) >> makefileTellMeWhatYouHaveSoFar.txt
lib.a: \
obj/file1.o \
obj/file2.o
ar -r lib.a $?
obj/file1.o:
# do some fortran precompiling stuff here for a specific file
obj/file2.o: $(SOURCE_PATH)/*.h precomp_path/*.h $(SOURCE_PATH)/file2.c precomp_path/%_l.h
cc -c -g file2.c
precomp_path/%_l.h : DatabaseForPreComp.txt
precomp_path/%_l.h :
$(foreach i , $(PREC_HEADERS) , $(DO_CPreComp) $(i) $(CPRECOMP);)
So that is my Makefile, the script for the DO_CPreComp looks as follows:
#!/bin/bash
filename="(basename "$1")"
dir="$(dirname "$1")"
cprecomptool="$2"
echo ${dir} ${filename} ${cprecomptool} >> scriptTellMeWhatYouKnow.txt
"${cprecomptool}" "precomp_path/${filename}.1" >&cprecomp.err
cp "precomp_path/${filename}.1" "precomp_path/${filename}"
So according to the makefileTellMeWhatYouHaveSoFar.txt I collect all the headers, obviously also the ones not specified with _l.h . This has space for improvement but the precompiler is smart enough to skip the files which are not suitable. So makefileTellMeWhatYouHaveSoFar.txt looks like that:
header1.h header2.h header2_l.h headerx_l.h headery_l.h headerz.h
The Error tells me:
path_to_here/do_cprec : line xy: $2: unbound variable
make[2]: *** [precomp_path/%_l.h] Error 1
make[1]: *** [lib.a] Error 2
scriptTellMeWhatYouKnow.txt shows me the script knows nothing and it is not even created. If I modify cprecomptool and directly add it in the script hardcoded the scriptTellMeWhatYouKnow.txt shows me the argument $(CPRECOMP) twice as file name and path name and the hardcoded precompiler. And ofc it ends up with Segmentation fault, so the header name was never handed over.
Additionally:
If I do not call the script in the second foreach but let $(i) be printed out with echo in another file it is empty.
Perhaps I am just too blind. And please if you are able to help me , explain it to me for dumb people, such that for the next time I stumble over a problem I am smarter because I know what I am doing. :)
OK, now that the main issue is solved, let's have a look at make coding styles. The make way of accomplishing what you want is not exactly using foreach in recipes. There are several drawbacks with this approach like, for instance, the fact that make cannot run parallel jobs, while it is extremely good at this. And on modern multi-core architectures, it can really make a difference. Or the fact that things are always redone while they are potentially up to date.
Assuming the result of the pre-compilation of foo_l.h file is a foo.h (we will look at other options later), the make way is more something like:
SOURCE_PATH := ./src
CPRECOMP := ./tools/cprecomp.exe
DO_CPreComp := $(SOURCE_PATH)/do_cprec
HDREXT := .h
PREC_HEADERS := $(wildcard $(addsuffix /*_l.$(HDREXT),$(SOURCE_PATH)))
PRECOMPILED_HEADERS := $(patsubst %_l.h,%.h,$(PREC_HEADERS))
$(PRECOMPILED_HEADERS): %_l.h: %.h DatabaseForPreComp.txt
$(DO_CPreComp) $# $(CPRECOMP)
($# expands as the target). This is a static pattern rule. With this coding style only the headers that need to be pre-compiled (because they are older than their prerequisites) are re-built. And if you run make in parallel mode (make -j4 for 4 jobs in parallel) you should see a nice speed-up factor on a multi-core processor.
But what if the pre-compilation modifies the foo_l.h file itself? In this case you need another dummy (empty) file to keep track of when a file has been pre-compiled:
SOURCE_PATH := ./src
CPRECOMP := ./tools/cprecomp.exe
DO_CPreComp := $(SOURCE_PATH)/do_cprec
HDREXT := .h
PREC_HEADERS := $(wildcard $(addsuffix /*_l.$(HDREXT),$(SOURCE_PATH)))
PREC_TAGS := $(patsubst %,%.done,$(PREC_HEADERS))
$(PREC_TAGS): %.done: % DatabaseForPreComp.txt
$(DO_CPreComp) $< $(CPRECOMP) && \
touch $#
($< expands as the first prerequisite). The trick here is that the foo_l.h.done empty file is a marker. Its last modification time records the last time foo_l.h has been pre-compiled. If foo_l.h or DatabaseForPreComp.txt has changed since, then foo_l.h.done is out of date and make re-builds it, that is, pre-compiles foo_l.h and then touch foo_l.h.done to update its last modification time. Of course, if you use this, you must tell make that some other targets depend on $(PREC_TAGS).
With the help of #Renaud Pacalet I was able to find a solution.
In the comments you can read further try & errors.
I am using GNU Make 3.82 Built for x86_64-redhat-linux-gnu . Seems like the foreach does not like the space behind the i or furthermore takes the space as part of the variable.
# ... like beforehand check out in the question
PREC_HEADERS=$(shell find $(SOURCE_PATH) -iname '*_l.h')
# nothing changed here in between...
$(foreach i,$(PREC_HEADERS),$(DO_CPC) $i $(CPC);)
This has the advantage that I only precompile the headers which have the _l.h - ending. Having the brackets $(i) around the $i or not, doesn't make a change. What really changed everything was the space behind the first i .
Good luck!
I download latex package on which I want do some changes, but in this packege exist file include.m4 and I don't know what it does and how it was generated. Here its lines:
m4_changequote([[, ]])m4_dnl
m4_dnl
m4_define([[m4_FILE_INIT]], [[m4_dnl
%
% This is automaticaly generated file, do not edit it.
%
]])m4_dnl
m4_dnl
m4_define([[m4_FILE_ID]], [[m4_dnl
m4_patsubst([[$1]], [[\$Date::? \([0-9]+\)-\([0-9]+\)-\([0-9]+\).*]], [[\1/\2/\3]])m4_dnl
v[[]]m4_ESKDX_VERSION]])m4_dnl
m4_dnl
m4_define([[m4_FILE_DATE]], [[m4_dnl
m4_patsubst([[$1]], [[\$Date::? \([0-9]+\)-\([0-9]+\)-\([0-9]+\).*]], [[\1/\2/\3]])]])m4_dnl
m4_dnl
Can you explain with which tool it was generated?
Thk. So this file is not autogenerated? ANd can you help me understand these lines from Makefile:
M4FLAGS = -P -Dm4_ESKDX_INIT="m4_include($(TOP_DIR)/include.m4)" \
-Dm4_ESKDX_VERSION=$(VERSION) -Dm4_ESKDX_DATE=$(RELEASE_DATE)
And rule:
%.def: %.def.in $(M4DEPS)
m4 $(M4FLAGS) $< >$#
%.sty: %.sty.in $(M4DEPS)
m4 $(M4FLAGS) $< >$#
%.cls: %.cls.in $(M4DEPS)
m4 $(M4FLAGS) $< >$#
As I can see GNU m4 options '-D' substitutes macro m4_ESKDX_INIT in .sty .cls files to m4_include(../include.m4) and then options '-P' first expands file include.m4 and furthemore expands macros in include.m4.
This is a macro for the GNU m4 macro processor. This file is designed to be used with the -P or --prefix-builtins commandline option. The m4_ part will be stripped away when m4 evaluates this file. This file doesn't do anything itself, it just defines three macros (FILE_INIT, FILE_ID and FILE_DATE) which presumably will be used in another step. You might want to look in the other files for references to this one. The basic idea will be to load this file before running another file through m4 and it will replace those macros as it goes.
The message about automatically generated is supposed to end up in the final file as a comment. As we can see in the rules in the Makefile, each of the .def, .sty and .cls files are generated from an equivalently named .in file (so result.cls will be built from result.cls.in. by evaluating the macros in these files and replacing them with the equivalents.
So, to modify these files, you will want to edit the .in files.
The standard version of syntaxhighlighter 3.0.83 ( http://alexgorbatchev.com/SyntaxHighlighter/download/ ) is similar to the plugin for Wordpress which contains an optional language pack ( http://wordpress.org/plugins/wp-syntaxhighlighter/ ) -- e.g., Biferno, Clojure, DOS batch file, F#, LISP, Lua (only for SyntaxHighlighter 3.0), MEL Script, Objective-C, PowerCLI, Processing, R, S, S-PLUS, Tcl, Verilog, Vim Script and YAML. I'm looking for a way to add the optional languages to the standard version -- any assistance in that regard would be appreciated.
Download the Wordpress plugin from: http://wordpress.org/plugins/wp-syntaxhighlighter/ As of the date of this answer, the most recent version was wp-syntaxhighlighter.1.7.3.zip
Extract the *.js and *.css files from the subfolders within the folder lang-pack-for-wp-syntaxhighlighter and organize them to your liking. In my case, I chose to place the *.js language files inside the folder syntaxhighlighter/scripts/ in the standard version. There was only one *.css file -- i.e., shBrushProcessing.css and I chose to place that inside the folder syntaxhighlighter/styles/ in the standard version.
In your *.html file, ensure the path to the brush javascript file is correct -- e.g., for lisp use:
<script type="text/javascript" src="syntaxhighlighter/scripts/shBrushLisp.js"></script>
In your *.html file, the brush must correspond to the brush javascript file -- e.g., for lispuse:
<pre class="brush: lisp">
I'm using PRE_TARGETDEPS to generate source files, and I'm adding the generated source files to SOURCES for compilation.
The output of my generator obviously doesn't exist at the time qmake is run, so qmake outputs WARNING: Failure to find: for each of the to-be-created source files.
How can I quell this warning, since I know my PRE_TARGETDEPS is going to produce those files?
Or, is there a better way to generate intermediate files using qmake?
Example
Here's a complete test.pro file that exhibits the problem:
TEMPLATE = lib
preprocess.commands += cat test.cc.in | sed 's/a/0/g' > test.0.cc ;
preprocess.commands += cat test.cc.in | sed 's/a/1/g' > test.1.cc ;
preprocess.depends = test.cc.in
QMAKE_EXTRA_TARGETS += preprocess
PRE_TARGETDEPS += preprocess
SOURCES = test.0.cc test.1.cc
Place this in an empty folder, and also create an empty test.cc.in file. Run qmake, and you'll see these warnings:
WARNING: Failure to find: test.0.cc
WARNING: Failure to find: test.1.cc
How can I quell this warning
From my reading of the qmake code, it looks like you can:
either have qmake ignore any filenames that don't exist - in which case they won't get built by your later steps
or have it write these warnings
I don't think either of these would be satisfactory for you.
Here's my reasoning.... I had a hunt for the text Failure to find in a Qt distribution I had to hand: qt4.8.1.
It appeared 3 times in in qmake/generators/makefile.cpp. The two blocks of code look like this:
QStringList
MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &vpath_var)
{
....
debug_msg(1, "%s:%d Failure to find %s in vpath (%s)",
__FILE__, __LINE__,
val.toLatin1().constData(), vpath.join("::").toLatin1().constData());
if(flags & VPATH_RemoveMissingFiles)
remove_file = true;
else if(flags & VPATH_WarnMissingFiles)
warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData());
....
else if(flags & VPATH_WarnMissingFiles)
warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData());
and this is called with:
l = findFilesInVPATH(l, (comp.flags & Compiler::CompilerRemoveNoExist) ?
VPATH_RemoveMissingFiles : VPATH_WarnMissingFiles, "VPATH_" + comp.variable_in);
So the flags parameter passed in to the first block will be either RemoveMissingFiles or WarnMissingFiles, depending on comp.flags & Compiler::CompilerRemoveNoExist.
Or, is there a better way to generate intermediate files using qmake?
I'm not sure that it's better - i.e. it's certainly complex - but this is what is done where I work...
In the .pro file, a system call is done, that:
generates the required files,
and then writes out their names to stdout.
Here's an example from the .pro, to show how it would be called:
SOURCES += $$system( python my_script_name.py )
You can of course pass arguments in to the python script, if you like
Things to note/limitations:
This means that the python script gets run whenever you run qmake, but not during individual make invocations
Each invocation of python really slows down our qmake steps - taking roughly twice as long as running qmake without launching python - but you could always use a different scripting language
This would fix your problem, in that by the time qmake processes the SOURCES value, the files have been created by the script.
According to this MSDN blog entry it is recommended to compile .fx effect files with fxc as part of your build process. Given a list of fx files, how do I tell cmake to add some to my project files (VS2010)?
Use find_program to find fxc and add_custom_command to build:
find_program(FXC fxc DOC "fx compiler")
if(NOT FXC)
message(SEND_ERROR "Cannot find fxc.")
endif(NOT FXC)
add_custom_target(fx ALL)
foreach(FILE foo.fx bar.fx baz.fx)
get_filename_component(FILE_WE ${FILE} NAME_WE)
add_custom_command(OUTPUT ${FILE_WE}.obj
COMMAND ${FXC} /Fo ${FILE_WE}.obj ${FILE}
MAIN_DEPENDENCY ${FILE}
COMMENT "Effect-compile ${FILE}"
VERBATIM)
add_dependencies(fx ${FILE_WE}.obj)
endforeach(FILE)
Not being a Windows user, I'm not sure if that's exactly the right way to invoke fxc, but you can tinker with it. Note also that this doesn't link the object files into wherever they need to go. This mailing list post might help you.