This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Python 2.7 build install fails intermittently with -j on MacOS
Type: behavior Stage: resolved
Components: Build Versions: Python 3.10
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: cheryl.sabella, iritkatriel, madscientist, martin.panter, ned.deily, willingc
Priority: normal Keywords: patch

Created on 2019-03-28 22:14 by madscientist, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 13186 closed sandy-lcq, 2019-05-08 09:16
Messages (8)
msg339078 - (view) Author: Paul Smith (madscientist) Date: 2019-03-28 22:14
Maybe no one cares anymore, but I've discovered that if I run make with -j the installation sometimes fails with this error:

install: mkdir /Users/build/.../dist/python/x86_64-darwin/lib: File exists

I believe it's because the targets altbininstall and libainstall as well as $(DESTSHARED) ($(BINLIBDEST)/lib-dynload) all contain a for loop which tries to create $(LIBDIR).  The makefile uses the install -d command to create directories and this command will fail if the directory already exists.

I haven't investigated the full dependency chain but at least two of the above targets don't have a relationship that forces make to avoid running them both at the same time.

Maybe a better solution would be to create a separate target like make-directories or something that creates all the directories and have the other targets depend on that one target.  Or something.

As it is, my MacOS builds fail about 1 in 5 times or similar.

Interestingly my Linux builds never fail.  Not sure if install works differently on Linux, or the timing is just different there.
msg339086 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2019-03-29 00:08
What version of macOS do you see this with and to what kind of macOS file system are you installing?  Also, is the failure seem with Python 3.x installs?  For what it's worth, I've never seen this and I do a *lot* of make installs on macOS but, while I usually do a make -j3 for the build steps, I rarely use -j on install steps as I doubt it has much positive effect there.
msg339089 - (view) Author: Carol Willing (willingc) * (Python committer) Date: 2019-03-29 01:47
Thanks @madscientist for filing an issue. It would be helpful to have a bit more detail on what specific MacOS version you are building on as well as the specific commands that you are executing.

Does this also happen if you run `make clean` before running a build?
msg339095 - (view) Author: Paul Smith (madscientist) Date: 2019-03-29 04:37
I've tried on both MacOS 10.12 and 10.14.  I'm using GNU make 4.2.1 (built myself, not the one that comes with Xcode).

I have not tried Python3 builds.  I agree with you that -jN probably has little impact on the install step, but the build infrastructure I'm using simply provides it by default on both the build and install steps.

All my builds are completely from scratch and scripted; I start with a tarball, unpack it, then do an out-of-tree builds that run configure, then run "make" then "make install".

Note that these commands are _themselves_ invoked from a makefile the controls the build so they are recursive make invocations and the parent make was started with -j8 or so, causing the child makes to inherit that parallelism.

I doubt much of that is relevant though.  Here's the issue:

  install: commoninstall ...

  commoninstall: ... altbininstall ... libainstall ...

  altbininstall: $(BUILDPYTHON)

  libainstall: all python-config

So, these two targets altbininstall and libainstall are both prerequisites of commoninstall, which is a prerequisite of install.

Since there's no dependency relationship between altbininstall and libainstall, make is free to run them both at the same time if you invoke it with parallelism enabled.

Both of these targets try to create directories; altbininstall uses:

        @for i in $(BINDIR) $(LIBDIR); \
        do \
                if test ! -d $(DESTDIR)$$i; then \
                        echo "Creating directory $$i"; \
                        $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \
                else    true; \
                fi; \
        done

and libainstall uses:

        @for i in $(LIBDIR) $(LIBP) $(LIBPL) $(LIBPC); \
        do \
                if test ! -d $(DESTDIR)$$i; then \
                        echo "Creating directory $$i"; \
                        $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \
                else    true; \
                fi; \
        done

You can see that both try to create the directory $(LIBDIR).  They do test for directory existence first but that's not sufficient when running in parallel: if they are running at the same time they might both test at the same time and succeed, then one will create the directory first.

Because the rule uses install -d, which (unlike mkdir -p for example) will fail if the directory already exists, you have a potential problem here.

If the Python 3 makefile has similar target constructs it will have the same issue.
msg339185 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2019-03-30 08:55
On Linux, Gnu’s “install” command is happy if the target directory already exists; it just changes the mode (-m) etc. So the race isn’t a big deal.

This is like the race I described (theoretical at the time) at <https://bugs.python.org/issue25696#msg255393>, although that is about $(LIBPC) not $(LIBDIR). I suggested adding a separate target (a bit like Paul’s “make-directories” suggestion; see my -4.patch in that bug), but it didn’t get much support.

A more conservative patch would be a phony target that retains the existing “if / echo / install” logic.
msg370425 - (view) Author: Cheryl Sabella (cheryl.sabella) * (Python committer) Date: 2020-05-31 11:49
Even though this mentions Python 2, the pull request is against master.
msg393773 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-05-16 23:59
I closed PR 13186 because the change in it was already committed under issue36464. Can this issue be closed now as well or is there anything left to look into?
msg393775 - (view) Author: Carol Willing (willingc) * (Python committer) Date: 2021-05-17 00:52
@iritkatriel Thanks for the follow up. I'm going to close this as I haven't seen any issues with -j on MacOS.
History
Date User Action Args
2022-04-11 14:59:13adminsetgithub: 80645
2021-05-17 00:52:08willingcsetstatus: open -> closed
resolution: not a bug
messages: + msg393775

stage: patch review -> resolved
2021-05-16 23:59:56iritkatrielsetnosy: + iritkatriel
messages: + msg393773
2020-05-31 11:49:38cheryl.sabellasetnosy: + cheryl.sabella
messages: + msg370425
2020-05-31 11:46:38cheryl.sabellasetversions: + Python 3.10, - Python 2.7
2019-05-08 09:16:39sandy-lcqsetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request13100
2019-03-30 08:55:46martin.pantersetnosy: + martin.panter

messages: + msg339185
stage: needs patch
2019-03-29 04:37:00madscientistsetmessages: + msg339095
2019-03-29 01:47:43willingcsetnosy: + willingc
messages: + msg339089
2019-03-29 00:08:46ned.deilysetnosy: + ned.deily
messages: + msg339086
2019-03-28 22:14:37madscientistcreate