4

When I have a make task where a specific target needs to be made before another, while in parallel mode, this is simple when using SunPro Make (dmake). The following makefile:

install:  dir dir/file

dir:
    mkdir dir

dir/file:
    cp source dir/file

could be made parallel make safe by changing the first line to:

install: dir .WAIT dir/file

or by using:

.NO_PARALLEL: install

The rest of the makefile will still be handled in parallel mode and even a list if targets to the left or to the right of .WAIT will be handled in parallel mode.

See: http://schilytools.sourceforge.net/man/man1/make.1s.html and http://schilytools.sourceforge.net/man/man1/dmake.1.html

but GNU make does not seem to have a similar option. Is there really no way to do this with GNU make?

To be more specific, the solution needs to be written in a way that allows the makefile to be processed with other make implementations.

The special target .WAIT could e.g. be in a make program dependent macro that is called e.g. $(WAIT)

Note that there is an apparent solution that does not help:

In theory one could make dir a dependency of dir/file in order to enforce to create dir before trying to copy to dir/file, but if you later copy another file into dir, this makes dir newer than dir/file. As a result, calling make more than once would copy to dir/fileagain and again, without the expected result from make to do the copy only in case that the source has become newer that dir/file.

This raises the alternate question whether there may be a topology of dependencies that enforces make to create dir before copying to dir/file without making dira dependency of dir/file.

  • 3
    Maybe I'm low on coffee, but wouldn't it be enough to make dir/file depend on dir? (that is, dir/file: dir) – njsg May 2 '18 at 20:42
  • 1
    If you do this and later copy more files into dir, then dir/file would become outdated from the view of make while it is really up to date. – schily May 2 '18 at 20:43
  • @schily: Oh, of course. – njsg May 2 '18 at 20:54
  • @stephen-penny: could you be more specific please? I cannot find .SECONDARY in the GNU make documentation. – schily May 2 '18 at 20:57
6

In GNU make, you can use order-only-prerequisites to make sure dir is created before the rule to create dir/file is run.

See this page for more details.

You can see from the example in GNU make's manual that it's really tailored for adding dependency on a directory being created before creating files under it.

In the case of your specific example, something like this should do it:

dir/file: | dir
        cp source dir/file

Though you don't need to modify the existing rule, you could just add that dependency somewhere else in your Makefile...

To be more specific, the solution needs to be written in a way that allows the makefile to be processed with other make implementations.

I don't think this would work in other make implementations... One possible solution is to create a GNUmakefile that would include the actual Makefile and also add GNU make specific extensions.

You could also probably make GNU make ignore a rule such as .WAIT by defining it as a dummy rule in your GNUmakefile.

I hope these pointers are helpful!

  • GNUmakefile is not a solution in anobject oriented makefile system. I did already mention to use $(WAIT) that could be empty or contain .WAIT. A feasible solution would be something that could be controlled by make macro content or by including different rule files. I need to have a look at your proposal and check how many gmake specific rule files I would need. This finally decides whether it could be done this way. – schily May 2 '18 at 22:08
  • I don't really know what you mean by object oriented makefile system... In any case, I don't think there's a way to have GNU make execute dependencies serially (when otherwise parallelizing.) In other words, I don't think something like .NO_PARALLEL: install exists in GNU make. Using order-only prerequisites (like explained above) should be able to get you to order directories before the files they contain, but the feature is unfortunately GNU make specific, so you need to find a way to trigger that in GNU make only and ignore it on other make implementations... – filbranden May 2 '18 at 22:15
  • The schily makefilesystem includes object specific make rules that depend on the task, the platform, the compiler and the make utility. This is implemented via make macros that contain strings that depend on the current environment. The content of the make macros is controlled via pattern macro expansions that are common to all modern make implementations. – schily May 3 '18 at 11:43
  • Based on your idea, I could create a useful solution. See my own answer to my question. – schily May 3 '18 at 13:27
4

You need to add dependencies so that directories are created before the files under them.

It is possible to use a "marker" file for the dependency on the directory, that way creating a file under it won't touch the timestamp of the directory. That doesn't require any GNU make specific features either.

In your example:

install: dir/file

dir/.marker:
        mkdir -p dir
        touch dir/.marker

dir/file: dir/.marker
        cp source dir/file

You can use something like .directory or .dir or .folder for the marker file...

  • .directory is used in KDE to store file manager metadata, so it would be safer to avoid this one. I personally think .created would be a nice choice. – Frax May 3 '18 at 0:43
  • I used this method in former times for directories that are created in the internal build tree, but it does not look nice if you e.g. create a marker file named /usr/share/man/man1/.marker – schily May 3 '18 at 10:55
  • 1
    @schily You could create the markers elsewhere, such as in the source tree, name them after the encoded directory. (With the drawback that removing the directory won't delete the marker.) Another option is incorporating the mkdir -p commands in each of the file rules. I still think the order-only prerequisites in GNU make are a better approach, assuming you can find a way to incorporate the proprietary feature into your build and have a fallback for it... – filbranden May 3 '18 at 11:17
1

Here is the my own answer that has been derived from the idea presented by Filipe Brandenburger and from generic methods used in the Schily Makefile system:

The makefile system makes sure that the following make macros are set up this way:

WAIT=       # empty with GNU make
WAIT= .WAIT # .WAIT special target with SunPro Make

MAKEPROG= <name of the make program> # This is from: smake, gmake, sunpro

_UNIQ= .XxZzy-

Now the makefile that makes use from the macro definitions above:

_NORULE=    $(_UNIQ)$(MAKEPROG)
__NORULE=   $(_NORULE:$(_UNIQ)gmake=)
NORULE=     $(__NORULE:$(_UNIQ)%=%)

install: dir $(WAIT) dir/file

dir/file: source
        cp source dir/file

dir:
        mkdir -p dir

$(NORULE)dir/file: | dir

$(NORULE) expands to nothing with gmake and to sunprowith SunPro Make.

In case of gmake, the whole makefile expands to:

install: dir dir/file

dir/file: source
        cp source dir/file

dir:
        mkdir -p dir

dir/file: | dir

In case of SunPro Make, the whole makefile expands to:

install: dir .WAIT dir/file

dir/file: source
        cp source dir/file

dir:
        mkdir -p dir

sunprodir/file: | dir

The last line is seen as a junk rule with no relevance.

  • 1
    Glad you figured it out and happy I could help! – filbranden May 3 '18 at 13:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.