Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing Build Regression [BISON] #892

Merged
merged 10 commits into from
Dec 26, 2023
Merged

Conversation

seanmorris
Copy link
Contributor

@seanmorris seanmorris commented Dec 22, 2023

What is this PR doing?

This PR corrects the same Bison2.7 issue as #871, in a much simpler fashion.

What problem is it solving?

Bison2.7 will not be built in some cases, blocking the build of PHP <= 7.3.

How is the problem addressed?

This invokes dependency builds before building PHP.

Testing Instructions

Checkout the branch & install the dependencies:

git checkout sm-make-deps-before-compile
npm install

In a separate terminal, clear the artifacts:

docker system prune -af
cd packages/php-wasm/compile
make clean

Run the build and ensure it succeeds:

npm run recompile:php:node
npm run recompile:php:web

Start the dev server:

npm run dev

Then, navigate to:

... and ensure that wordpress works as-expected in each environment.

@seanmorris seanmorris changed the title Fixing Build Regression [Part II - ALT] Fixing Build Regression [BISON] Dec 22, 2023
@seanmorris seanmorris self-assigned this Dec 22, 2023
@seanmorris seanmorris requested a review from adamziel December 22, 2023 01:27
@seanmorris seanmorris added [Type] Bug An existing feature does not function as intended [Feature] PHP.wasm labels Dec 22, 2023
@dmsnell
Copy link
Member

dmsnell commented Dec 25, 2023

Hm. I was trying to test this but npm install and npm ci both fail when attempting to compile vips, claiming that libarchive isn't available. I have node@21.1.0 and npm@8.11.0, and although I don't think it should matter, I actually have libvips and livarchive installed on my system via Homebrew.

npm ERR! Package libarchive was not found in the pkg-config search path.
npm ERR! Perhaps you should add the directory containing `libarchive.pc'
npm ERR! to the PKG_CONFIG_PATH environment variable
npm ERR! Package 'libarchive', required by 'vips', not found

I reviewed the project README and I'm not seeing any obvious missing dependency. Clearing out node_modules didn't help either. Do you have any advice on this? @seanmorris

@dmsnell
Copy link
Member

dmsnell commented Dec 25, 2023

Do you have any advice on this? @seanmorris

Interestingly, I removed vips from my machine and the dependencies built fine. Not sure why, but that's not fun. Created #904 to note it.

@dmsnell
Copy link
Member

dmsnell commented Dec 25, 2023

Ran some smoke tests and everything seemed to be working across various PHP versions.

The node build took 24 min to complete
The web build took around 28 min to complete

@@ -167,7 +167,10 @@ if (!requestedVersion || requestedVersion === 'undefined') {
const sourceDir = path.dirname(new URL(import.meta.url).pathname);

// Build the base image
await asyncSpawn('make', ['base-image'], { cwd: sourceDir, stdio: 'inherit' });
await asyncSpawn('make', ['all', 'base-image'], {
Copy link
Member

Choose a reason for hiding this comment

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

does the base-image depend on the all target or is that incidental here?

otherwise it seems like the Makefile would be the place to list dependencies, wouldn't it? why aren't we putting it there?

Copy link
Contributor Author

@seanmorris seanmorris Dec 26, 2023

Choose a reason for hiding this comment

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

@dmsnell The base-image target does not depend on the all target.

base-image: base-image/.ready
base-image/.ready:

(Its generally poor practice to use a PHONY target as a dependency because that means anything downstream from that target would be rebuilt on every invocation.)

Copy link
Contributor Author

@seanmorris seanmorris Dec 26, 2023

Choose a reason for hiding this comment

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

@dmsnell Actually its fine so long as phony targets are used as dependencies ONLY of other phony targets:

.PHONY: all libz libzip libpng16 libxml2 libopenssl libsqlite3 libiconv libncurses libedit bison2.7 oniguruma base-image clean
all: libz libzip libpng16 libxml2 libopenssl libsqlite3 libiconv libncurses libedit bison2.7 oniguruma base-image
clean:

Copy link
Member

Choose a reason for hiding this comment

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

@seanmorris I think we might have jumped a little too quickly here. I wasn't asking if base-image currently is encoded as depending on all, but rather was asking about your change, which seemed to be encoding a dependency outside of the Makefile. previously we asked for base-image, but with your change we were also asking for all. this communicated to me that all is necessary to build base-image, and if that were actually true then I think it would be best to leave the dependencies inside make where they are handled robustly.

as for .PHONY I think there may also be some misunderstandings. we should use them wherever they are part of a dependency hierarchy, whether or not they are a dependency of another .PHONY or not. the distinction is purely whether the .PHONY targets need to be rebuilt every time make runs. for example, it could be that some build target needs to download a configuration from the internet. that download would be a candidate .PHONY target, but that doesn't force other targets to rebuild because we could make those other targets depend on the downloaded configuration file directly, and simply not update it if the download is the same as it previously was.

.PHONY: fetch-config
fetch-config:
	curl https://my.site/config.json -o /tmp/config.json
	diff -q -s /tmp/config.json ./config.json
	if [ $? -ne 0 ]; then mv /tmp/config.json ./config.json; fi

libsomething: ./config.json
	build-lib-something

making all a .PHONY target is common because people generally don't want to put sub-dependencies on the all target, and even if all is .PHONY and runs every time, if the dependencies of the dependencies haven't changed than nothing much will run.

so we want to be judicious and thoughtful when applying .PHONY, but it's also not something we want to try and avoid; we only want to understand its purpose and value and use it where appropriate.


I can see that we have a number of ways we could improve the Makefile, but those don't need to occur in this PR.

@seanmorris seanmorris requested a review from dmsnell December 26, 2023 20:11

# If you write a rule whose recipe will not create the target file,
# the recipe will be executed every time the target comes up for remaking.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
Copy link
Member

Choose a reason for hiding this comment

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

Generally I love comments like this, but I also think it's okay if we don't add it, because .PHONY is a pretty standard feature of Makefile syntax and there should be ample documentation available for someone to understand it. We don't document the other parts of the Makefile syntax here, and it's probably okay to let the PHONY exist as is.

# If you write a rule whose recipe will not create the target file,
# the recipe will be executed every time the target comes up for remaking.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: all libz libzip libpng16 libxml2 libopenssl libsqlite3 libiconv libncurses libedit bison2.7 oniguruma base-image clean
Copy link
Member

Choose a reason for hiding this comment

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

do all of these need to be .PHONY? I wouldn't ask other than it seems like this patch is now adding that property to the targets, and it wasn't there before.

of course, adding .PHONY will ensure they're built every time we run make, but particularly for the libraries like libpng16 and libzip it seems like we could be more efficient in general if we based the build on some deterministic element like a version number, build architecture, or source files, etc…

I guess the important question is whether you found something in this PR that was broken because dependencies didn't get rebuilt when they should have. if that's the case then .PHONY seems like a fair addition; if not, maybe we let it stay the way it was and address that separately.

Copy link
Contributor Author

@seanmorris seanmorris Dec 26, 2023

Choose a reason for hiding this comment

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

The Makefile should have originally listed these targets as .PHONY because the names being used are the same as the directories in which the actual artifacts lie. Unintentionally, if that directory has a modification date newer than its dependencies, it would then INCORRECTLY be marked as cached and skipped. Adding the .PHONY target instructs Make to skip looking at the directory modification time and instead look at the listed dependencies only.

Copy link
Member

Choose a reason for hiding this comment

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

Great. This makes more sense now, as I didn't realize that the directories of the same name as the phony targets existed (because I hadn't looked that deeply outside of the diff).

Let's make sure to add this in the commit description, that this fixes a bug we already had, wherein the .PHONY should have always been there.

rm -rf ./libedit/dist
rm -rf ./bison2.7/dist
rm -rf ./oniguruma/dist

Copy link
Member

Choose a reason for hiding this comment

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

these don't need to appear first. without any arguments, make will run the first target, which is why all is a common first target. clean doesn't need to move unless there's a reason to do it.

@@ -167,7 +167,10 @@ if (!requestedVersion || requestedVersion === 'undefined') {
const sourceDir = path.dirname(new URL(import.meta.url).pathname);

// Build the base image
await asyncSpawn('make', ['base-image'], { cwd: sourceDir, stdio: 'inherit' });
await asyncSpawn('make', [], {
Copy link
Member

Choose a reason for hiding this comment

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

it would be nice here to leave some explicit intention in the code. although it happens to work with the changes you made to the Makefile, we've lost the linkage between asking for what we want (with the pre-existing base-image) and running make and hoping it does what we need (because no more target is listed).

adding base-image here would be helpful, or all, or anything to communicate to our future selves what our purupose was in running make.

@@ -167,7 +167,10 @@ if (!requestedVersion || requestedVersion === 'undefined') {
const sourceDir = path.dirname(new URL(import.meta.url).pathname);

// Build the base image
await asyncSpawn('make', ['base-image'], { cwd: sourceDir, stdio: 'inherit' });
await asyncSpawn('make', ['all', 'base-image'], {
Copy link
Member

Choose a reason for hiding this comment

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

@seanmorris I think we might have jumped a little too quickly here. I wasn't asking if base-image currently is encoded as depending on all, but rather was asking about your change, which seemed to be encoding a dependency outside of the Makefile. previously we asked for base-image, but with your change we were also asking for all. this communicated to me that all is necessary to build base-image, and if that were actually true then I think it would be best to leave the dependencies inside make where they are handled robustly.

as for .PHONY I think there may also be some misunderstandings. we should use them wherever they are part of a dependency hierarchy, whether or not they are a dependency of another .PHONY or not. the distinction is purely whether the .PHONY targets need to be rebuilt every time make runs. for example, it could be that some build target needs to download a configuration from the internet. that download would be a candidate .PHONY target, but that doesn't force other targets to rebuild because we could make those other targets depend on the downloaded configuration file directly, and simply not update it if the download is the same as it previously was.

.PHONY: fetch-config
fetch-config:
	curl https://my.site/config.json -o /tmp/config.json
	diff -q -s /tmp/config.json ./config.json
	if [ $? -ne 0 ]; then mv /tmp/config.json ./config.json; fi

libsomething: ./config.json
	build-lib-something

making all a .PHONY target is common because people generally don't want to put sub-dependencies on the all target, and even if all is .PHONY and runs every time, if the dependencies of the dependencies haven't changed than nothing much will run.

so we want to be judicious and thoughtful when applying .PHONY, but it's also not something we want to try and avoid; we only want to understand its purpose and value and use it where appropriate.


I can see that we have a number of ways we could improve the Makefile, but those don't need to occur in this PR.

Copy link
Member

@dmsnell dmsnell left a comment

Choose a reason for hiding this comment

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

Thanks @seanmorris - looks good in the merge.

@seanmorris seanmorris merged commit 1ef5bf6 into trunk Dec 26, 2023
5 checks passed
@seanmorris seanmorris deleted the sm-make-deps-before-compile branch December 26, 2023 23:41
@adamziel
Copy link
Collaborator

adamziel commented Dec 27, 2023

Just to confirm — does this PR:

  • Only rebuilds bison and only if needed (e.g. missing pre-built library or an architecture mismatch)?
  • Reuses the pre-built wasm artifacts shipped with the repo for libpng and other libraries?

Or does it always trigger a full rebuild? It’s not apparent to me from the description and I’d like to avoid a full rebuild each time.

if this Pr only rebuilds bison, we’re good. However, if it does trigger a full rebuild, let’s revert and explore what I suggested in the other PR: #871 (comment)

@dmsnell
Copy link
Member

dmsnell commented Dec 28, 2023

sorry @adamziel for missing the comment you linked; I may have misunderstood this PR's goal, which I took from the PR's description and chats with @seanmorris.

as he and I discussed, I think there definitely are mislabeled or missing dependencies, and it sounds like your suggestion would address that more directly.

if there's a problem occurring because we're not building bison, this PR fixes that problem bluntly by making sure it's built while building the base image.

I'll let @seanmorris share his thoughts before I do any reverts, as I think we can still move the two ideas together first by making the build slow but reliable (if this does that) and then by optimizing the Makefile.

adamziel pushed a commit that referenced this pull request Jan 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] PHP.wasm [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants