How do I create a makefile rule to run astyle? - formatting

I'd like to create a makefile rule to run astyle on any writable source files. Currently, I have a rule like the following:
style:
find . -perm -200 -regex ".*[.][CHch]p*" -exec astyle --suffix=none --style=ansi --convert-tabs "{}" \;
This rule basically works but doesn't seem to be the make way of doing things.

Assuming you have a list of source files (or can create them with the shell function), something like:
style : $(SOURCES:.cpp=.astyle-check-stamp)
astyle $(ASTYLEFLAGS) $< && touch $#
would be the make-style. It would re-check each changed source file with astyle and skipped already checked files.

Related

Make pattern match variables are not expanded

I'm trying to build some PDFs in a Makefile using Sphinx. The resulting PDF has broken references, so I want to fix those using pdftk.
Goal
So what I want to do for all PDFs I build is this:
# Creates the PDF files.
$(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) source/pdf/ $(BUILDDIR)/pdf_broken
# Go through all PDFs and fix them.
pdftk $(BUILDDIR)/pdf_broken/thepdf.pdf output $(BUILDDIR)/pdf/thepdf.pdf
Attempt with Make
So to do this with Make I have written this Makefile:
# Build PDF (results in broken references)
$(BUILDDIR)/pdf_broken/%.pdf:
$(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) source/pdf/ $(BUILDDIR)/pdf_broken
# This fixes the broken pdfs and produces the final result.
$(BUILDDIR)/pdf/%.pdf: $(BUILDDIR)/pdf_broken/%.pdf
mkdir -p $(BUILDDIR)/pdf/
pdftk $^ output $#
pdf: $(BUILDDIR)/pdf/%.pdf
Expected result
I'm using Pattern matching as I understand it from reading the manual:
http://www.tack.ch/gnu/make-3.82/make_91.html
Where $< as I understand it should be the prerequisite expanded so from my above example:
$(BUILDDIR)/pdf_broken/thepdf.pdf
and then $# should be the target:
$(BUILDDIR)/pdf/thepdf.pdf
So my recipe pdftk $^ output $# should run the command:
pdftk $(BUILDDIR)/pdf_broken/thepdf.pdf output $(BUILDDIR)/pdf/thepdf.pdf
Actual result
But this is not what is happening. Instead, this is run:
pdftk build/pdf_broken/%.pdf output build/pdf/%.pdf
Which obviously gives me an error:
Error: Unable to find file.
Error: Failed to open PDF file:
build/pdf_broken/%.pdf
Question
So my question is, what have I missundestood with how the pattern matching works, and how is the correct way to solve this using Make?
You should likely lookup pattern rules. In any case, it looks like you have a single command to generate all the files in the broken directory. This should have its own rule, and should likely output a dummy file to indicate it is complete. Your rule to fix the pdf files should be dependent on this dummy target being created.
It should be something like:
// get a list of expected output files:
PDF_SOURCES:=$(wildcard source/pdf/*)
PDF_OUTS:=$(patsubst $(PDF_SOURCES),source/pdf/%.pdf,$(BUILDDIR)/pdf/%.pdf);
// just for debugging:
$(info PDF_SOURCES = $(PDF_SOURCES))
$(info PDF_OUTS = $(PDF_OUTS))
// default rule
all: $(PDF_OUTS)
#echo done
// rule to build BUILDIR:
$(BUILDDIR)/pdf:
mkdir -p $#
// rule to build all broken files in one go:
// (note: generates a file .dosphynx, which is used to keep track
// of when the rule was run last. This rule will be run if the
// timestamp of any of the sources are newer.
.do_sphynx: $(PDF_SOURCES) | $(BUILDDIR)/pdf
$(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) source/pdf/ $(BUILDDIR)/pdf_broken
touch $#
// create a dependency of all output files on do_sphynx
$(PDF_OUTS): .do_sphynx
// patern rule to fix pdf files
$(BUILDDIR)/pdf/%.pdf : $(BUILDDIR)/pdf_broken/%.pdf
pdftk $< output $#
I've not tested this, so its possible it may have a syntax error in it..
---------------------- EDIT -------------
Ok, since $(PDF_OUTS) cannot be determined at makefile read time, perhaps you should do:
// get a list of expected output files:
PDF_SOURCES:=$(wildcard source/pdf/*)
all: .do_fix
#echo done
$(BUILDDIR)/pdf:
mkdir -p $#
.do_sphynx: $(PDF_SOURCES) | $(BUILDDIR)/pdf
$(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) source/pdf/ $(BUILDDIR)/pdf_broken
touch $#
.do_fix: .do_sphynx
#for src in $$(ls source/pdf/*.pdf); do \
trg=$${src/#"source/pdf"/"$(BUILD_DIR)/pdf"}; \
[[ $$src -nt $$trg ]] && \
echo "$$src ==> $$trg" && pdftk $$src output $$trg; \
done
touch $#
One note -- the -nt comparator in the if will return true if $trg does not exist, so it will cover the case where the file is missing, or the target is older than the source. Again not tested, but it should work.

Build kernel module into a specific directory

is there a way to set a output-directory for making kernel-modules inside my makefile?
I want to keep my source-direcory clean from the build-files.
KBUILD_OUTPUT and O= did not work for me and were failing to find the kernel headers when building externally.
My solution is to symlink the source files into the bin directory, and dynamically generate a new MakeFile in the bin directory. This allows all build files to be cleaned up easily since the dynamic Makefile can always just be recreated.
INCLUDE=include
SOURCE=src
TARGET=mymodule
OUTPUT=bin
EXPORT=package
SOURCES=$(wildcard $(SOURCE)/*.c)
# Depends on bin/include bin/*.c and bin/Makefile
all: $(OUTPUT)/$(INCLUDE) $(subst $(SOURCE),$(OUTPUT),$(SOURCES)) $(OUTPUT)/Makefile
make -C /lib/modules/$(shell uname -r)/build M=$(PWD)/$(OUTPUT) modules
# Create a symlink from src to bin
$(OUTPUT)/%: $(SOURCE)/%
ln -s ../$< $#
# Generate a Makefile with the needed obj-m and mymodule-objs set
$(OUTPUT)/Makefile:
echo "obj-m += $(TARGET).o\n$(TARGET)-objs := $(subst $(TARGET).o,, $(subst .c,.o,$(subst $(SOURCE)/,,$(SOURCES))))" > $#
clean:
rm -rf $(OUTPUT)
mkdir $(OUTPUT)
If you are building inside the kernel tree you can use the O variable:
make O=/path/to/mydir
If you are compiling outside the kernel tree (module, or any other kind of program) you need to change your Makefile to output in a different directory. Here a little example of a Makefile rule which output in the MY_DIR directory:
$(MY_DIR)/test: test.c
gcc -o $# $<
and then write:
$ make MY_DIR=/path/to/build/directory
The same here, but I used a workaround that worked for me:
Create a sub-directory with/for every arch name (e.g. "debug_64").
Under "debug_64": create symbolic link of all .c and .h files. Keeping the same structure.
Copy the makefile to "debug_64" and set the right flags for 64 Debug build, e.g.
ccflags-y := -DCRONO_DEBUG_ENABLED
ccflags-y += -I$(src)/../../../lib/include
KBUILD_AFLAGS += -march=x86_64
Remember to set the relative directories paths to one level down, e.g. ../inc will be ../../inc.
Repeat the same for every arch/profile.
Now we have one source code, different folders, and different make files.
By the way, creating profiles inside make files for kernel module build is not an easy job, so, I preferred to create a copy of makefile for every arch.

Can someone help explain this code? It is a shell script for creating a checksum list

#!/bin/bash
# create a list of checksums
cat /dev/null > MD5SUM
for i in */*/*.sql ; do test -e $i && md5sum $i >>MD5SUM ; done
Then this command is used to check to see if anything has changed:
md5sum -c MD5SUM
It works fine and everything. I just don't really understand how. Say if I wanted to make a checksum list of all the files in my home directory $HOME how can I do that? What does the */*/*.sql part of the for loop mean? I'm assuming that is to display SQL files only but how can I modify that? Say I wanted all files in the directory? Why is it not just *.sql ? What does the rest of the for loop do in this case?
Lets go by parts:
cat /dev/null > MD5SUM
this will only "erase" the previous MD5SUM file/list that was created before.
for i in */*/*.sql;
this will iterate over files that are 2 directories deep from your current folder. If you have folders
~/a/b
~/c/d
~/e/f
and you run your script in your home folder (~) all "*.sql" inside directories b,d,f will have the checksum calculated and piped to a file MD5SUM in the current direcotry:
do test -e $i && md5sum $i >>MD5SUM ; done
Now Answering your questions:
Say if I wanted to make a checksum list of all the files in my home directory $HOME how can I do that?
I would use the find command with the exec option
find $HOME -maxdepth 1 -name \*.sql -exec md5sum {} \;
What does the //*.sql part of the for loop mean?
I answered it above, anyway only goes 2 directories deep before getting to the files.
I'm assuming that is to display SQL files only but how can I modify that? Say I wanted all files in the directory?
Change
for i in */*/*.sql;
to
for i in */*/*;
or for current directory
find $HOME -maxdepth 1 -name \* -exec md5sum {} \;
Why is it not just *.sql ? What does the rest of the for loop do in this case?
Explained before.
Hope it helps =)

How do I handle spaces in a script that uses the results of find in a for loop?

I am trying to write a simple command that searches through a music directory for all files of a certain type and copies them to a new directory. I would be fine if the files didn't have spaces.
I'm using a script from the following question, but it fails for spaces:
bash script problem, find , mv tilde files created by gedit
Any suggestions on how I can handle spaces, once I'm satisfied that all the files are being listed, I'll change echo to cp
for D in `find . -name "*.wma*"`; do echo "${D}"; done
You probably want to do this instead:
find . -name *.wma -exec echo "{}" \;

Makefile to archive/link together auto-generated source files

Basically, I have a file 'blah.txt'. That files gets parsed by a 'compiler' and from it will generate N output .c files. I want a makefile that will from that .txt file generate the c files then compile all of them and archive them in a libmystuff.a
I tought of something like this :
all: dogen libmystuff.a
dogen: source.txt
mycompiler $^
libmystuff.a: $(addsuffix .o, $(shell ls *.c))
$(AR) rcs $# $^
.PHONY: dogen
But obviously that doesn't work because the dependencies are evaluated at the start and at that point the *.c just doesn't yield anything yet since they don't exist.
Does anyone see how to accomplish that (without listing all the generated *.c explicitely) ?
Use sentry "makefile" to force make to re-read makefile and substitute correct list at *.c:
include sources-sentry
sources-sentry: source.txt
mycompiler $^
touch $#
libmystuff.a: $(addsuffix .o, $(shell ls *.c))
$(AR) rcs $# $^
include directive is used to include other makefiles (just like C's #include). It has a nice pecularity that if makefile it includes is a target itself, make program first considers it as a target and tries to update. If it is not up-to-date, make invokes the commands needed to update it and then re-reads makefile, substituting all the variables again.
Thus, if source.txt changed since the last time you processed it (the time being recorded as timestamp of sources-sentry file), the sources will be updated and make will be re-invoked, the *.c being substituted to the updates set of c-files.
Pavel Shved is right(*), you must rerun Make. Here is a trick I'm rather proud of. It will handle dependencies on objects that may not yet exist, and won't run unnecessarily.
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
all: libmystuff.a
ifeq ($(MAKELEVEL),0)
libmystuff.a: source.txt
mycompiler $^
#$(MAKE) -s $#
else
libmystuff.a: $(OBJECTS)
$(AR) rcs $# $^
endif
(*) My old nemesis, we meet again.
EDIT:
If some other make calls this make... I hadn't thought of that. But I think this will solve it:
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
all: libmystuff.a
libmystuff.a: source.txt
mycompiler $^
#$(MAKE) -s phonyLib
.PHONY: phonyLib
phonyLib: $(OBJECTS)
$(AR) rcs libmystuff.a $^
(Yes, I know, if you feel an urge to build a file called "phonyLib" you won't be able to do it with this makefile, but let's not be perverse.)
If your .c files are only produced by the .txt, then you can let the libmystuff.a depend on the txt, and evaluate the $(shell ls *.c) in the rule body instead.