Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@jlmuir
Copy link

@jlmuir jlmuir commented Nov 17, 2016

A parallel make (e.g., make -j 4) can sometimes fail when making the object files because the object file targets do not depend on the objects target which creates the objects directory in which the object files are to be created. If an object file target is executed before the objects target (or at least before the objects target finishes executing), the build will fail because the objects directory has not been created yet.

Here's an example failure where the objects/os_mac_conv.o target has executed before the objects target:

--- objects ---
--- auto/osdef.h ---
--- objects/os_macosx.o ---
--- objects/os_mac_conv.o ---
--- objects ---
--- auto/osdef.h ---
CC="clang -Iproto -DHAVE_CONFIG_H   -I/usr/include -DMACOS_X_UNIX    " srcdir=. sh ./osdef.sh
--- objects/os_macosx.o ---
clang -c -I. -Iproto -DHAVE_CONFIG_H   -I/usr/include -DMACOS_X_UNIX  -O2 -pipe -I/usr/include -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1       -o objects/os_macosx.o os_macosx.m
--- objects/os_mac_conv.o ---
clang -c -I. -Iproto -DHAVE_CONFIG_H   -I/usr/include -DMACOS_X_UNIX  -O2 -pipe -I/usr/include -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1       -o objects/os_mac_conv.o os_mac_conv.c
--- objects/os_macosx.o ---
error: unable to open output file 'objects/os_macosx.o': 'No such file or directory'
--- objects/os_mac_conv.o ---
error: unable to open output file 'objects/os_mac_conv.o': 'No such file or directory'
1 error generated.
--- objects/os_macosx.o ---
1 error generated.
--- objects/os_mac_conv.o ---
*** [objects/os_mac_conv.o] Error code 1

The failure can be reliably reproduced by adding a delay to the objects target in src/Makefile to induce the bad execution ordering:

objects:
	sleep 5
	mkdir -p objects

Then run a parallel make (e.g., make -j 4).

This pull request fixes the problem by adding the objects target as a dependency of the object file targets and by adding a -p option to the objects target's mkdir invocation since the objects directory can exist.

The same problem exists in Vim 7.4, so if a patch could be issued for that version too, that would be great! Thanks!

The objects target creates the objects directory.  The object files are
created inside the objects directory, but the object file targets don't
specify the objects target as a dependency.  For a parallel make (e.g.,
make -j 4), this can lead to a build failure if an object file target is
executed before the objects target is executed.

For example, if the objects/os_macosx.o target is executed before the
objects target, then the build will try to create os_macosx.o inside the
objects directory, but that will fail because the objects directory does
not exist yet.

To fix this, add the objects target as a dependency of all object file
targets, and add a -p option to mkdir in the objects target since the
objects directory can already exist.
@brammool
Copy link
Contributor

Lewis Muir wrote:

A parallel make (e.g., make -j 4) can sometimes fail when making the
object files because the object file targets do not depend on the
objects target which creates the objects directory in which the
object files are to be created. If an object file target is executed
before the objects target (or at least before the objects target
finishes executing), the build will fail because the objects
directory has not been created yet.

Here's an example failure where the objects/os_mac_conv.o target has executed before the objects target:

--- objects ---
--- auto/osdef.h ---
--- objects/os_macosx.o ---
--- objects/os_mac_conv.o ---
--- objects ---
--- auto/osdef.h ---
CC="clang -Iproto -DHAVE_CONFIG_H   -I/usr/include -DMACOS_X_UNIX    " srcdir=. sh ./osdef.sh
--- objects/os_macosx.o ---
clang -c -I. -Iproto -DHAVE_CONFIG_H   -I/usr/include -DMACOS_X_UNIX  -O2 -pipe -I/usr/include -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1       -o objects/os_macosx.o os_macosx.m
--- objects/os_mac_conv.o ---
clang -c -I. -Iproto -DHAVE_CONFIG_H   -I/usr/include -DMACOS_X_UNIX  -O2 -pipe -I/usr/include -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1       -o objects/os_mac_conv.o os_mac_conv.c
--- objects/os_macosx.o ---
error: unable to open output file 'objects/os_macosx.o': 'No such file or directory'
--- objects/os_mac_conv.o ---
error: unable to open output file 'objects/os_mac_conv.o': 'No such file or directory'
1 error generated.
--- objects/os_macosx.o ---
1 error generated.
--- objects/os_mac_conv.o ---
*** [objects/os_mac_conv.o] Error code 1

The failure can be reliably reproduced by adding a delay to the
objects target in src/Makefile to induce the bad execution
ordering:

objects:
  sleep 5
  mkdir -p objects

Then run a parallel make (e.g., make -j 4).

This pull request fixes the problem by adding the objects target as
a dependency of the object file targets and by adding a -p option to
the objects target's mkdir invocation since the objects
directory can exist.

The same problem exists in Vim 7.4, so if a patch could be issued for
that version too, that would be great! Thanks!

Parallel make isn't really supported.

This patch causes "make" to build all the objects every time.

The only backup you need is the one that you didn't have time for.
(Murphy)

/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \
\ an exciting new programming language -- http://www.Zimbu.org ///
\ help me help AIDS victims -- http://ICCF-Holland.org ///

To support parallel make by ensuring that the objects directory gets
created before the object file targets write to it, the objects target
was added as a dependency of the object file targets.  This had the
unfortunate side effect of causing all object files to be built every
time (I assume because writing to the objects directory caused the
last-modified time of the objects directory to be updated).  Revert that
dependency, and instead make each object file target create the objects
directory before creating the object file in it.
@jlmuir
Copy link
Author

jlmuir commented Nov 17, 2016

On 11/17, Bram Moolenaar wrote:

Parallel make isn't really supported.

OK, I didn't know that. Is your position that you don't want to support
it, or are you open to fixes that make it work?

This patch causes "make" to build all the objects every time.

Rats! Sorry about that. OK, I've pushed another commit that keeps the
"-p" option addition to the mkdir in the objects target, but reverts the
addition of the objects target as a dependency on each of the object
file targets, and instead makes each object file target ensure the
objects directory has been created before writing the object file to it.

src/Makefile Outdated
mkdir -p objects

objects/arabic.o: arabic.c
objects/arabic.o: objects arabic.c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use an order-only dependency so this file is not rebuilt when the directory timestamp changes:

objects/arabic.o: arabic.c | objects
        ...

Although TBH I'm not sure if that's a GNU Make extension, or if it's portable enough to be acceptable to Vim...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I intentionally did not use that since it's a GNU Make feature. NetBSD's Make, for example, does not support that. (NetBSD's Make has a special .ORDER target that I think tries to solve a similar problem.) I thought the Vim developers wouldn't be too excited about making GNU Make a requirement for building. And even if they were OK with it, my personal preference would be to not introduce a requirement on a specific Make implementation.

BTW, I made a second commit that reverts the addition of the objects dependency on the object file targets since Bram noted that that caused the object files to be built every time. Now, each object file target ensures the objects directory is created before creating the object file in it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, each object file target ensures the objects directory is created before creating the object file in it.

I think this might be slow. A different approach to consider is to depend on something like objects/.dirstamp and create objects directory in rules for objects/.dirstamp target. This is how automake and probably some other build systems do it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, interesting. I like that better than having the mkdir in each of the object file targets. I just pushed another commit that implements your suggestion. Thanks!

The object file targets need to depend on the objects target to ensure
the objects directory gets created before creating an object file in it.
However, adding the objects target as a dependency has the undesirable
side effect of causing Make to think that the object files are out of
date whenever it tries to build them, so they are built every time.  To
overcome this, the creation of the objects directory was moved into
each object file target.  Then, it was suggested by GitHub user xaizek
in a GitHub code review comment that a better approach would be to
use the DIR/.dirstamp idiom for a dependency on directory DIR.  This
implements that suggestion, thereby removing the need to create the
objects directory in each object file target.
@vim-ml
Copy link

vim-ml commented Nov 19, 2016

On Fri, Nov 18, 2016 at 8:48 AM, Marius Gedminas
[email protected] wrote:

@mgedmin commented on this pull request.


In src/Makefile:

-objects/arabic.o: arabic.c
+objects/arabic.o: objects arabic.c

You should use an order-only dependency so this file is not rebuilt when the
directory timestamp changes:

objects/arabic.o: arabic.c | objects
...

Although TBH I'm not sure if that's a GNU Make extension, or if it's
portable enough to be acceptable to Vim...

Isn't there a "gmake" (i.e. GNU make) program, available for use even
on platforms such as Windows, where most GNU utilities are not
installed?

Best regards,
Tony.

@jlmuir
Copy link
Author

jlmuir commented Nov 19, 2016

On 11/18, vim-dev ML wrote:

Isn't there a "gmake" (i.e. GNU make) program, available for use
even on platforms such as Windows, where most GNU utilities are not
installed?

Yes, there are ports of GNU Make for Windows, but they don't come
pre-installed. And of course there are more platforms than just Windows
and Linux. I think the main concern here is with creating a requirement
to use GNU Make for the build. If I'm on NetBSD, for example, I'd like
to be able to use the Make that comes with the base system; it would
seem really lame to have to install GNU Make just to build Vim.

@jlmuir
Copy link
Author

jlmuir commented Nov 28, 2016

Ping?

@brammool brammool closed this in 327054d Dec 1, 2016
@jlmuir
Copy link
Author

jlmuir commented Dec 5, 2016

Hello, Bram! I see you did not commit my fix but rather something else to address the issue. That's fine with me, and thanks for committing it! Unfortunately, what you committed does not seem quite right; there's still a dependency bug which can be recreated by adding a delay to the objects objects/.dirstamp target to force an unfavorable ordering for a parallel build.

Here's how to reproduce it:

$ git clone https://github.com/vim/vim.git
$ cd vim
$ ./configure

Add a delay (i.e., sleep 5 in this case) to the objects objects/.dirstamp target in src/Makefile to force an unfavorable ordering:

objects objects/.dirstamp:
	sleep 5
	mkdir -p objects
	touch objects/.dirstamp

Run a parallel build:

$ make -j 4

On macOS Sierra (10.12.1), this results in the following:

Starting make in the src directory.
If there are problems, cd to the src directory and run make there
cd src && /Library/Developer/CommandLineTools/usr/bin/make first
sleep 5
sleep 5
CC="gcc -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX    " srcdir=. sh ./osdef.sh
creating auto/pathdef.c
cd xxd; CC="gcc" CFLAGS="-DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1" LDFLAGS="-L/usr/local/lib" \
		/Library/Developer/CommandLineTools/usr/bin/make -f Makefile
gcc -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -L/usr/local/lib -DUNIX -o xxd xxd.c
gcc -c -I. -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX  -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1        -o objects/main.o main.c
error: unable to open output file 'objects/main.o': 'No such file or directory'
1 error generated.
make[1]: *** [objects/main.o] Error 1
make[1]: *** Waiting for unfinished jobs....
mkdir -p objects
mkdir -p objects
touch objects/.dirstamp
touch objects/.dirstamp
make: *** [first] Error 2

@xaizek
Copy link

xaizek commented Dec 5, 2016

$(OBJ_COMMON) doesn't include several .o-files, including objects/main.o. Looks like $(OBJ) is the right variable to use. Also objects itself should depend on objects/.dirstamp to make sure those rules are run at most once. This patch seems to work:

 src/Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index a24eb7b..38f5cb2 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1705,7 +1705,7 @@ OBJ_MESSAGE_TEST = \
 
 MESSAGE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MESSAGE_TEST)
 
-ALL_OBJ = $(OBJ_COMMON) $(OBJ_JSON_TEST) $(OBJ_MEMFILE_TEST) $(OBJ_MESSAGE_TEST)
+ALL_OBJ = $(OBJ) $(OBJ_JSON_TEST) $(OBJ_MEMFILE_TEST) $(OBJ_MESSAGE_TEST)
 
 
 PRO_AUTO = \
@@ -2862,7 +2862,8 @@ auto/gui_gtk_gresources.h: gui_gtk_res.xml $(GUI_GTK_RES_INPUTS)
 # commands understand putting object files in another directory, it must be
 # specified for each file separately.
 
-objects objects/.dirstamp:
+objects: objects/.dirstamp
+objects/.dirstamp:
 	mkdir -p objects
 	touch objects/.dirstamp
 

@brammool
Copy link
Contributor

brammool commented Dec 5, 2016 via email

@jlmuir
Copy link
Author

jlmuir commented Dec 5, 2016

@brammool, yes, that patch works for me.

FYI, not a big deal, but it executes the mkdir -p objects and the touch objects/.dirstamp twice: once for the objects target and a second time for the objects/.dirstamp target:

$ make -j 4
Starting make in the src directory.
If there are problems, cd to the src directory and run make there
cd src && /Library/Developer/CommandLineTools/usr/bin/make first
CC="gcc -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX    " srcdir=. sh ./osdef.sh
creating auto/pathdef.c
cd xxd; CC="gcc" CFLAGS="-DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1" LDFLAGS="-L/usr/local/lib" \
		/Library/Developer/CommandLineTools/usr/bin/make -f Makefile
gcc -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -L/usr/local/lib -DUNIX -o xxd xxd.c
mkdir -p objects
mkdir -p objects
touch objects/.dirstamp
touch objects/.dirstamp
gcc -c -I. -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX  -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1        -o objects/arabic.o arabic.c
[snip]

If you separated the targets and made the objects target have no commands and just a dependency on the objects/.dirstamp target as suggested by @xaizek, it would only execute those commands once.

@brammool
Copy link
Contributor

brammool commented Dec 6, 2016 via email

desvp pushed a commit to desvp/vim that referenced this pull request May 30, 2017
Problem:    Parallel make fails. (J. Lewis Muir)
Solution:   Make sure the objects directory exists. (closes vim#1259)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants