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

Use cmake to build wasmtime-c-api #9031

Merged
merged 16 commits into from
Aug 9, 2024
Merged

Conversation

CGamesPlay
Copy link
Contributor

This resolves #8890, and allows a rust project to use the wasmtime-c-api crate again.

In #8642, the build process was changed but the rust build script was not changed to match. In addition, because the CMake configuration invokes cargo, it isn't possible for cargo to then invoke CMake (cylic dependency). To resolve this, we introduce a new CMake target that only produces the necessary files for the build to succeed, and then allow cargo to build the API as normal.

I've tested that this works in my local copy of tree-sitter, which depends on the wasmtime-c-api-impl crate.

@CGamesPlay CGamesPlay requested review from a team as code owners July 29, 2024 04:34
@CGamesPlay CGamesPlay requested review from fitzgen and removed request for a team July 29, 2024 04:34
@github-actions github-actions bot added the wasmtime:c-api Issues pertaining to the C API. label Jul 29, 2024
Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

Thanks! Do you know if it's possible to have an install target which only installs header files? That way there wouldn't need to be two includes and only one would be necessary.

Additionally can you forward along the -D flags for the features of Wasmtime? Otherwise the conf.h could report the wrong set of supported features.

@CGamesPlay
Copy link
Contributor Author

Sure, we just need to use COMPONENT Headers, see docs. I think only having one header would be ideal, especially if they are in different directories.

Are you suggesting that instead of just generating the header, I install all the headers to the cargo output directory, and then report that as the sole include directory? That makes sense, I just want to confirm.

@CGamesPlay
Copy link
Contributor Author

Updated commits properly configure the headers, and install all headers to the right place, so we can get rid of the second metadata variable.

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

Thanks!

@alexcrichton alexcrichton added this pull request to the merge queue Jul 30, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 30, 2024
@clason
Copy link

clason commented Jul 30, 2024

Can this be backported to release-23, too?

@alexcrichton
Copy link
Member

I think that would be reasonable yeah, just needs to land on main first and then the backport is a cherry-pick + new PR.

I believe CI is failing here on MinGW for cmake-related reasons? (compiler detection not working presumbably because cl.exe is used when mingw flags are passed)

@maxbrunsfeld
Copy link
Contributor

Is there any way we could avoid adding this cmake build dependency to wasmtime-c-api-impl?

Could the build.rs just generate conf.h, instead of using cmake to do it? It looks like that build.rs file already has to explicitly list out a bunch of cargo features and convert them to C macro names. Could it just write that to a conf.h file directly, instead of passing them as arguments to cmake?

Maybe I'm missing something, and the CMake build is doing something too significant to duplicate, but if not, it would be great to avoid the build-time dependency.

@alexcrichton
Copy link
Member

Is the cmake dependency too heavy for end users to arrange? I do think it's nice to have the same logic not duplicated. It's already broken once now so keeping it synchronized seems like the best bet.

@maxbrunsfeld
Copy link
Contributor

maxbrunsfeld commented Jul 30, 2024

I just anticipate that consumers of the tree-sitter crate won't necessarily have cmake installed on their CI / dev machines, if they are mainly set up for Rust development. It's not the end of the world, but it adds one more gotcha and potentially dependency issue for users of the crate.

Just to double check, I think that if we wanted to avoid requiring Cmake, we'd change this:

    let dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
    let mut config = cmake::Config::new(&dir);
    config
        .define("WASMTIME_DISABLE_ALL_FEATURES", "ON")
        .always_configure(true)
        .build_target("headers");
    for f in FEATURES {
        if env::var_os(format!("CARGO_FEATURE_{}", f)).is_some() {
            config.define(format!("WASMTIME_FEATURE_{}", f), "ON");
        }
    }
    let dst = config.build();

into this (or something similar).

    let prefix = "#ifndef WASMTIME_CONF_H\n#define WASMTIME_CONF_H\n";
    let suffix = "#endif\n";

    let mut header = prefix.to_string();
    for f in FEATURES {
        if std::env::var_os(format!("CARGO_FEATURE_{}", f)).is_some() {
            writeln!(&mut header, "WASMTIME_FEATURE_{}", f);
        }
    }
    header += suffix;

And you wouldn't need to add the headers target to the cmake file. It doesn't seem any more brittle to me. Either way, the build script needs to know the set of features, and how they map to C macro names.

@alexcrichton
Copy link
Member

The brittle part is that it's a duplication of copying over headers and there is no longer a single source of truth for how headers are created. Additionally there are no tests in this repository testing the header as-generated by the build script and without that there's also no tests that the duplicated logic for the header file generation is correct. What you're describing is correct as-is today but that may not hold true indefinitely into the future.

@maxbrunsfeld
Copy link
Contributor

maxbrunsfeld commented Jul 31, 2024

Oh, I would have thought that if there are tests for wasmtime-c-api, then they would cover the correctness of the wasmtime-c-api-impl build script. Is there a tested code path that doesn't run this build script?

Edit - Sorry never mind, it doesn't matter that much, and I don't want to hold this up.

@CGamesPlay
Copy link
Contributor Author

CGamesPlay commented Jul 31, 2024

Is there are test that mingw compilation is working at all presently? This invocation of cmake looks correct, but it detects MSVC anyways:

    running: "cmake" "D:\\a\\wasmtime\\wasmtime\\crates\\c-api"
        "-G" "MSYS Makefiles"
        "-DWASMTIME_DISABLE_ALL_FEATURES=ON"
        "-DWASMTIME_FEATURE_DISABLE_LOGGING=ON"
        "-DCMAKE_SYSTEM_NAME=Windows"
        "-DCMAKE_SYSTEM_PROCESSOR=AMD64"
        "-DCMAKE_INSTALL_PREFIX=D:\\a\\wasmtime\\wasmtime\\target\\x86_64-pc-windows-gnu\\release\\build\\wasmtime-c-api-impl-dfbdb5120f123319\\out"
        "-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -m64"
        "-DCMAKE_CXX_FLAGS= -ffunction-sections -fdata-sections -m64"
        "-DCMAKE_ASM_FLAGS= -ffunction-sections -fdata-sections -m64"
        "-DCMAKE_BUILD_TYPE=MinSizeRel"
    -- The C compiler identification is MSVC 19.40.33812.0

Updated

Looking at another mingw job I see that C:/msys64/usr/bin/pacman.exe -S --needed mingw-w64-x86_64-gcc --noconfirm and possibly a few others are likely needed?

@CGamesPlay
Copy link
Contributor Author

CGamesPlay commented Jul 31, 2024

I've added a workflow change to include the commands that I suspect fix the issue. And I rebased.

@alexcrichton
Copy link
Member

I've added an extra commit to this PR which runs the full tests suite on this PR instead of waiting for the merge queue, and it looks like there may still be some CI issues

@CGamesPlay
Copy link
Contributor Author

The one remaining CI failure is a network failure. Changes made to make CI happy:

  • Force CC and CXX in mingw. Turns out the other mingw build configurations don't build the C API anyways.
  • Use cargo package --no-verify on the C API since it is hard-coded to create an artifact directory in the source directory and it isn't possible to package that directory because cargo is hard-coded to exclude any directory with Cargo.toml in it.
    • By the way, the --no-verify on wasi-nn seems unnecessary (it worked fine on my machine).

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

Thanks! Given the possible fragility here with packaging and how you had to modify include, could verification via publish.rs be made to work? Basically could this be updated to undo the addition of --no-verify?

As for wasi-nn, if you'd like I think it's reasonable to try dropping that here too (and verify it), but it's ok to defer that to a different PR as well.

Comment on lines 102 to 104
# Note: this line will *always* create ${CMAKE_CURRENT_SOURCE_DIR}/artifact
# during the configure stage of cmake, and there does not seem to be a way to
# disable this behavior. This prevents cargo package from verifying the package.
Copy link
Member

Choose a reason for hiding this comment

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

Should the BINARY_DIR configuration be dropped entirely? That should probably be somewhere within CMAKE_CURRENT_BINARY_DIR if it's still being used to avoid modifying the source tree.

@CGamesPlay
Copy link
Contributor Author

The remaining 2 build failures were pretty simple tweaks, so I went ahead and made them. The CI is passing now, and I confirmed that it still works when referenced from a rust crate. There was a network failure int he build, but I rebased to trigger a test rerun.

Do you think this is good to merge in its latest state?

@@ -345,6 +345,9 @@ semver = { version = "1.0.17", default-features = false }
# in configuring binary size and or exploring the binary size implications of
# various features. Most features are enabled by default but most embeddings
# likely won't need all features.
#
# When adding or removing a feature, make sure to kepe the C API in sync by
Copy link

Choose a reason for hiding this comment

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

Suggested change
# When adding or removing a feature, make sure to kepe the C API in sync by
# When adding or removing a feature, make sure to keep the C API in sync by

@@ -11,22 +11,22 @@
* are three mechanisms for yielding control from wasm to the caller: fuel,
* epochs, and async host functions.
*
* When WebAssembly is executed, a #wasmtime_call_future_t is returned. This
* When WebAssembly is executed, a `wasmtime_call_future_t` is returned. This
Copy link

Choose a reason for hiding this comment

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

unrelated changes?

Copy link
Member

Choose a reason for hiding this comment

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

I found this was necessary at one stage of testing to appease doxygen. That being said I barely understanding doxygen and we could very well be holding doxygen wrong where this should work when it doesn't.

@@ -22,6 +23,8 @@
#cmakedefine WASMTIME_FEATURE_ASYNC
#cmakedefine WASMTIME_FEATURE_CRANELIFT
#cmakedefine WASMTIME_FEATURE_WINCH
// ... if you add a line above this be sure to change the other locations
// marked WASMTIME_FEATURE_LIST
Copy link

Choose a reason for hiding this comment

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

If you move this comment above the list (here and elsewhere), then you can avoid the duplicate nonce (less noise when grepping).

Copy link
Member

Choose a reason for hiding this comment

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

Personally I like having this at the end because features are often added at the end and a comment only at the top might get missed. The amount of duplication here though is unfortunate across the codebase but that would probably be best fixed with a "tidy" script or something like that rather than relying on us humans to handle everything.

Copy link

Choose a reason for hiding this comment

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

I just mean as a trivial way to halve the number of hits: no need to have the nonce both before and after the list; once is enough (no matter where).

Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

Ah thanks for debugging that! This looks good to me yeah, so I'm going to go ahead and merge. I'm going to follow up with some responses to @clason as well and there can always be follow-ups too to handle things.

@alexcrichton alexcrichton added this pull request to the merge queue Aug 9, 2024
Merged via the queue into bytecodealliance:main with commit 22a4480 Aug 9, 2024
123 checks passed
@clason
Copy link

clason commented Aug 9, 2024

And also backport (24.0 is probably good enough) ;)

@CGamesPlay
Copy link
Contributor Author

CGamesPlay commented Aug 12, 2024

I'd definitely love to get this in 24, and 23 would be nice if possible. Link to @clason's backport PRs:

alexcrichton added a commit that referenced this pull request Aug 12, 2024
* Use cmake to build wasmtime-c-api

* Properly expose features when building via cmake

* Install all headers to same directory

* Add vets

* attempt to fix ci

* Run all tests on CI

prtest:full

* Set CARGO_BUILD_TARGET; add CMakeLists to package

* Update comment on github action

* Attempt to fix android build

* Fix source dir modifications of c-api build

* Re-add BINARY_DIR option

* Fix build

* Move header installation to a cmake script

Try to avoid dealing with cmake configuration/platforms/etc.

* Tweak build of headers

* Install headers in build dir for examples

* Add cmake files to dist, fix header install dir

---------

Co-authored-by: Ryan Patterson <cgamesplay@cgamesplay.com>
Co-authored-by: Alex Crichton <alex@alexcrichton.com>
alexcrichton added a commit that referenced this pull request Aug 12, 2024
* Use cmake to build wasmtime-c-api

* Properly expose features when building via cmake

* Install all headers to same directory

* Add vets

* attempt to fix ci

* Run all tests on CI

prtest:full

* Set CARGO_BUILD_TARGET; add CMakeLists to package

* Update comment on github action

* Attempt to fix android build

* Fix source dir modifications of c-api build

* Re-add BINARY_DIR option

* Fix build

* Move header installation to a cmake script

Try to avoid dealing with cmake configuration/platforms/etc.

* Tweak build of headers

* Install headers in build dir for examples

* Add cmake files to dist, fix header install dir

---------

Co-authored-by: Ryan Patterson <cgamesplay@cgamesplay.com>
Co-authored-by: Alex Crichton <alex@alexcrichton.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasmtime:c-api Issues pertaining to the C API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

#include <wasmtime/conf.h> fails since conf.h is not generated
4 participants