Sed script behaves differently on similar platforms - gcc

I am building a project from Cygwin. Among other things, the GCC compiler creates dependency files, and then a sed script is called to "fix" the dependency files.
After the script finishes, on one system the dependency files contain, as example, this:
src/man/man.o: \[LF]
../include/debug.h \[LF]
../include/sys.h ../include/types.h \[LF]
and on the another system line endings are changed by the script to:
src/man/man.o: /[CR][LF]
../include/debug.h /[CR][LF]
../include/sys.h ../include/types.h /[CR][LF]
The second case with forward slashes and [CR][LF] breaks the build.
Why would the script behave differently?
Here is the critical sed line:
#sed -i -e's/\\\(.\)/\/\1/g' $(#:.o=.d) ;\
Could anyone decipher why is it system dependent?

sed -i -e's/\\\(.\)/\/\1/g'
Find a backslash (\\), followed by something (.) (i.e., not at end-of-line), and replace it with forward slash, plus whatever it was that followed (\1)...
$(#:.o=.d)
...in dependency files...? (Haven't seen this before, but it looks like "the corresponding .d for each .o.)
The rest looks unrelated to your problem.
I guess this is part of a crude way to turn Windows paths into Unix paths... and I guess the <CR> in there (no idea where that came from) makes this fail to operate correctly.
What happens if you add a dos2unix before that to get rid of the <CR>?
define DEPEND_HACK
#dos2unix $(#:.o=.d) ;\
sed -i -e's/\\\(.\)/\/\1/g' $(#:.o=.d) ;\
....

Related

Is it possible to execute all make commands that match a pattern?

Suppose I define several make PHONY commands:
auto-build-foo
auto-build-bar
auto-build-biz
...
auto-build-inf
And I can observe them all with the following keystrokes in bash with autocompletion configured:
$: make auto-build-<tab><tab>
auto-build-foo
auto-build-bar
auto-build-biz
...
auto-build-inf
Then my natural unix instinct is to write:
make auto-build-*
To build them all.
I understand this sort of thing needs to be implemented in make as a feature, a makefile as some sort of rule system, or some custom shell that integrates bash-completion history with some make-specialized interpretation.
But it would cool and useful to get this "out-of-the-box".
Is there such a mechanism that is -- or will be -- in GNU make?
No, GNU Make command line argument do not support wildcard.
But, you can easily do the job in bash:
One by one
$ for t in $(sed -e '/auto-build/!d' -e 's/:.*$//' -e 's/\n/ /' Makefile); do make "$t" ; done
At once
$ my_targets=$(sed -e '/auto-build/!d' -e 's/:.*$//' -e 's/\n/ /' Makefile)
$ make "$my_targets"
From a Makefile perspective, if you create your own, an efficient way could be to encapsulate the targets in a variable each time you write them:
TARGET:=auto-build-foo
$(TARGET):
#echo "$#"
ALL_TARGETS:=$(ALL_TARGETS) $(TARGET)
TARGET:=auto-build-bar
$(TARGET):
#echo "$#"
ALL_TARGETS:=$(ALL_TARGETS) $(TARGET)
auto-all: $(ALL_TARGETS)
.PHONY: auto-all
will give:
$ make auto-all
auto-build-foo
auto-build-bar
I think such a feature doesn't exist because many makefiles are written with an incomplete dependency graph; command line parameters - which tend to be recorded nowhere - are the main reason for this. Targets built for foo may introduce bugs when being reused as-is for bar - the usual procedure is to require an intermediate make clean to prevent this. The problem is that, given the current (and unlikely to change) execution logic of make, within one run there is no way to execute clean more than once, much less in an order which would not defy the purpose of make (partial updates) at all. I think the original use case for makefiles was more around single-purpose project building rather than a cross-over of dependency and batch processing. From a modern build system perspective this looks like a shortcoming, OTOH it is this focused simplicity which makes it the means of choice for many projects.

Finding dependencies by grep in Make

I'm working on a rather large project in pure C, and for various reasons we are not using CMake.
We have a good system which uses various shell commands to require very little maintanence. It will automatically find new headers and C files and add the headers to the dependencies and will compile the C files and include them in the output. However, we've gotten to the point where any changes we make to the header files becomes a problem because it requires a recompilation of the entire project, rather than just the C files that include it directly or indirectly.
I've worked on a system to ensure that the only header files which are added as dependencies are ones which are required by the C file itself (recursively up the tree).
I had thought I would be able to solve this myself, but it seems that make has rather inconsistent rules for expansion of variables.
The solution I came up with was to try to use ag and get all the includes out of the file. This works as intended, and I pipe it into tr so that I can ensure that no newlines are added, thereby messing up make. The issue that I'm having though is in determining which file to search in. This is the recipe that it's using for the section in question:
$(GAMEOBJDIR)/%.o : $(GAMEDIR)/%.c $(shell ag -o '(?<=(^#include "))(.*?)(?=("$$))' $(GAMEDIR)/%.c | tr '\n' ' ')
$(CC) $(CFLAGS) $(if $(RELEASE),$(RELFLAGS),$(DBFLAGS)) -c -o $# $<
The problem is that $(GAMEDIR)/%.c is expanding to src/game/%.c and not src/game/<filename>.c. I'm unsure how to fix this issue based on the expansion rules of make.
Once I can figure this out I'll be able to make sure this walks up the chain of header files too, but until I can get this figured out I have no reason to work on that.
Make's rules for expansion are completely consistent... but sometimes they aren't what people want. That's not the same thing :)
Rules for expansion are explained in the manual. In your case you're working with a prerequisite list which means the variables are expanded as the makefile is parsed. That includes the shell command and all other variables. Because you are working with a pattern rule, it means that at the time the makefile is parsed it doesn't match any particular file, it's just defining the pattern rule itself. So, % can't be expanded here. It will be expanded later, when make starts walking the dependency graph and trying to locate ways to build targets.
In general your method cannot work efficiently. You could defer the expansion of these parts of the prerequisites list using Secondary Expansion. However, that means every time make wants to TRY to use this pattern it will run these commands--that will just be slow.
Have you considered using a more standard way to manage detecting prerequisites? Try reading this description for example to see if it would work for you.

Missing separator in Makefile

So here's the thing.
I'm trying to build pngwriter. In the makefile there's a line saying:
include make.include
The file make.include has the function to specify the platform used via a symlink, it has just one line:
make.include.linux
(there's a file in the same directory called make.include.linux which has some necessary settings. And by the way, I'm doing this on Windows with MinGW)
in the msys shell, when I do make, it says:
make.include:1: *** missing separator. Stop.
I've looked at other missing separator posts and they're about spaces/tabs, which I think it's not the case here. I've searched about makefiles, symlinks, separators and could solve it.
Please help!
EDIT! OK, so make.include.linux isn't a command, it's a file whose contents need to be included in the original makefile. The make.include should be, as I read, a symlink to make.include.linux.
What you have there isn't valid make syntax. Commands can only be run as part of a target recipe. In your case it seems like what you want is:
all:
make.include.linux
Assuming that make.include.linux is a command, and not something else. Make sure the indentation is a tab character.

Gnu make : using content of file as recipe

Consider having a makefile, which can generate some files using generating lines listed in a file. For example file 001 using first line, 002 using second line, etc.
This file can be changed (it has it's own dependences, but this doesn't metter).
If some lines in this file changed, appropriate files should be remade. But other files shouldn't.
The solution I found is this one: for every file there is flag-file which content is generating line it was made last time. After remaking file with generating lines, i check all this file, and remove them if line changed. So files which have dependences on removed files will be remade, and other files won't. But this works too slow if use msys-make.
Can you suggest any other solution, which doesn't need many extra calls to file system and executable runs.
If I understand your description correctly, what you're describing is a Makefile which depends on another file that is functionally a Makefile but for unknown reasons uses a different format.
Turn that file into Makefile format and include it into the original Makefile. (If you're using GNU Make.)
We have what may be similar to your problem. We have xml files, say foobar.xml which contains the dependencies for foobar.out
<files>
<file>a</file>
<file>b</file>
<file>c</file>
</files>
We decided to adhere to this simple layout, so we don't need to parse xml. We use makepp (because we got fed up with gmake not noticing dependencies like changed commands). This gives us the builtin &sed command (the expression is actually Perl programming, but as you see, you don't need to get into it much). Here's what we do with three simple substitutions for the three kinds of lines:
%.d: %.xml
&sed 's!<files>!$(stem).out: \\! || s!<file>(.+)</file>!$$1 \\! || s!</files>!!' \
$(input) -o $(output)
include foobar.d
This produces foobar.d which we then include:
foobar.out: \
a \
b \
c \
Stackoverflow is swallowing the last empty line here, which avoids having to worry about the trailing backslash.

Can GNU make handle spaces?

I have a makefile that has C INCLUDES with spaces in them. There is no way for me to get around having to have the spaces in the file names. Is there any way to have spaces in file names with gnu make?
Make has some basic support for this by escaping spaces in filenames, in that the following Makefile will correctly compile and recompile the C file foo bar.c:
foo\ bar: foo\ bar.c
gcc -o "${#}" "${<}"
However, you have to be super-careful in quoting every command you run, and variables that are space-separated lists of files—e.g., SRCS, LIBS—won’t work, although it’ß possible that with enough hacking using Make text functions you can parse out the quotes and get everything working…
So while there is rudimentary support for spaces in filenames in rules and patterns, anything complicated is going to be an awful lot of very hard and frustrating work.

Resources