Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions pylib/gyp/generator/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,27 @@ def WriteSources(
self.WriteLn(f"{obj}: {gch}")
self.WriteLn("# End precompiled header dependencies")

# A prefix header may include generated headers, so the .gch has to
# wait for the same generated inputs the objects wait for. The rules
# above give the objects these as order-only prerequisites; without
# the same rules here the .gch races code generation, and a clean
# build fails on a missing generated header.
gchs = sorted({gch for _, _, gch in pchdeps})
if deps:
self.WriteMakeRule(
gchs,
deps,
comment="Make sure our dependencies are built before the pch.",
order_only=True,
)
if extra_outputs:
self.WriteMakeRule(
gchs,
extra_outputs,
comment="Make sure our actions/rules run before the pch.",
order_only=True,
)

if objs:
extra_link_deps.append("$(OBJS)")
self.WriteLn(
Expand Down
23 changes: 23 additions & 0 deletions test/fixtures/pch_prefix.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
'targets': [
{
'target_name': 'pch_prefix',
'type': 'executable',
'sources': [ 'pch.cc' ],
'xcode_settings': {
'GCC_PREFIX_HEADER': 'pch.h',
'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
},
# A prefix header is allowed to include generated headers, so the .gch has
# to wait for this target's actions the same way its objects do.
'actions': [
{
'action_name': 'make_header',
'inputs': [],
'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/generated.h' ],
'action': [ 'touch', '<(SHARED_INTERMEDIATE_DIR)/generated.h' ],
},
],
},
]
}
31 changes: 31 additions & 0 deletions test/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
fixture_dir = os.path.join(os.path.dirname(__file__), "fixtures")
gyp_file = os.path.join(fixture_dir, "integration.gyp")
pch_gyp_file = os.path.join(fixture_dir, "pch.gyp")
pch_prefix_gyp_file = os.path.join(fixture_dir, "pch_prefix.gyp")

if sys.platform == "win32":
sysname = sys.platform
Expand Down Expand Up @@ -80,6 +81,36 @@ def test_cmake(self) -> None:
assert_file(self, "out/Default/CMakeLists.txt", "cmake/CMakeLists.txt")


class TestGypMac(unittest.TestCase):
def setUp(self) -> None:
if sysname != "darwin":
self.skipTest("macOS-only test")
shutil.rmtree(os.path.join(fixture_dir, "out"), ignore_errors=True)

def test_make_prefix_header_waits_for_generated_inputs(self) -> None:
rc = gyp.main(
[
"-f",
"make",
"--depth",
fixture_dir,
"--generator-output",
"out",
pch_prefix_gyp_file,
]
)
assert rc == 0

with open(os.path.join(fixture_dir, "out/pch_prefix.target.mk")) as in_file:
mk = in_file.read()

gch = "$(obj).target/$(TARGET)/pch-cc/pch.h.gch"
assert f"$(obj).target/$(TARGET)/pch.o: {gch}" in mk
# A prefix header may include generated headers, so the .gch must carry
# the same order-only prerequisites the objects carry.
self.assertRegex(mk, re.escape(f"{gch}: |") + r".*make_header")


class TestGypWindows(unittest.TestCase):
def setUp(self) -> None:
if sys.platform != "win32":
Expand Down