Unverified Commit 000e8b0d authored by Matteo Bigoi's avatar Matteo Bigoi Committed by GitHub
Browse files

Allow to build and test on MacOX M1/x86 chips (#1609)

* Allow to build and test on MacOX M1 chips

* Add MacOS linker config

* Fall back to standard event loop if uvloop is not available
parent 430f4bf8
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
# See: https://pyo3.rs/latest/building_and_distribution.html?highlight=rustflags#macos
[target.x86_64-apple-darwin]
rustflags = [
  "-C", "link-arg=-undefined",
  "-C", "link-arg=dynamic_lookup",
]

[target.aarch64-apple-darwin]
rustflags = [
  "-C", "link-arg=-undefined",
  "-C", "link-arg=dynamic_lookup",
]
+13 −5
Original line number Diff line number Diff line
OS := $(shell uname -s)
SRC_DIR := $(shell git rev-parse --show-toplevel)
CUR_DIR := $(shell pwd)
GRADLE := $(SRC_DIR)/gradlew
@@ -5,8 +6,15 @@ SERVER_SDK_DST := $(CUR_DIR)/pokemon-service-server-sdk
CLIENT_SDK_DST := $(CUR_DIR)/pokemon-service-client
SERVER_SDK_SRC := $(SRC_DIR)/codegen-server-test/python/build/smithyprojections/codegen-server-test-python/pokemon-service-server-sdk/rust-server-codegen-python
CLIENT_SDK_SRC := $(SRC_DIR)/codegen-test/build/smithyprojections/codegen-test/pokemon-service-client/rust-codegen

SHARED_LIBRARY_DST := $(CUR_DIR)/libpokemon_service_server_sdk.so
ifeq ($(OS), Darwin)
	DEBUG_SHARED_LIBRARY_SRC := $(SRC_DIR)/target/debug/libpokemon_service_server_sdk.dylib
	RELEASE_SHARED_LIBRARY_SRC := $(SRC_DIR)/target/release/libpokemon_service_server_sdk.dylib
else
	DEBUG_SHARED_LIBRARY_SRC := $(SRC_DIR)/target/debug/libpokemon_service_server_sdk.so
	RELEASE_SHARED_LIBRARY_SRC := $(SRC_DIR)/target/release/libpokemon_service_server_sdk.so
endif

all: codegen

@@ -18,11 +26,11 @@ codegen:

build: codegen
	cargo build
	ln -sf $(DEBUG_SHARED_LIBRARY_SRC) $(CUR_DIR)/libpokemon_service_server_sdk.so
	ln -sf $(DEBUG_SHARED_LIBRARY_SRC) $(SHARED_LIBRARY_DST)

release: codegen
	cargo build --release
	ln -sf $(RELEASE_SHARED_LIBRARY_SRC) $(CUR_DIR)/libpokemon_service_server_sdk.so
	ln -sf $(RELEASE_SHARED_LIBRARY_SRC) $(SHARED_LIBRARY_DST)

run: build
	python $(CUR_DIR)/pokemon_service.py
@@ -37,6 +45,6 @@ clean:
	cargo clean || echo "Unable to run cargo clean"

distclean: clean
	rm -rf $(SERVER_SDK_DST) $(CLIENT_SDK_DST) $(CUR_DIR)/Cargo.lock $(CUR_DIR)/libpokemon_service_server_sdk.so
	rm -rf $(SERVER_SDK_DST) $(CLIENT_SDK_DST) $(CUR_DIR)/Cargo.lock $(SHARED_LIBRARY_DST)

.PHONY: all
+21 −0
Original line number Diff line number Diff line
@@ -18,6 +18,27 @@ can be used directly.

`make distclean` can be used for a complete cleanup of all artefacts.

### Uvloop

The server can depend on [uvloop](https://pypi.org/project/uvloop/) for a
faster event loop implementation. Uvloop can be installed with your favourite
package manager or by using pip:

```sh
pip instal uvloop
```

and it will be automatically used instead of the standard library event loop if
it is found in the dependencies' closure.

### MacOs

To compile and test on MacOs, please follow the official PyO3 guidelines on how
to [configure your linker](https://pyo3.rs/latest/building_and_distribution.html?highlight=rustflags#macos).

Please note that the `.cargo/config.toml` with linkers override can be local to
your project.

## Run

`cargo run` can be used to start the Pokémon service on
+24 −4
Original line number Diff line number Diff line
@@ -178,7 +178,9 @@ impl PyApp {
    /// Python asynchronous loop needs to be started and handled during the lifetime of the process.
    /// First of all we install [uvloop] as the main Python event loop. Thanks to libuv, uvloop
    /// performs ~20% better than Python standard event loop in most benchmarks, while being 100%
    /// compatible.
    /// compatible. If [uvloop] is not available as a dependency, we just fall back to the standard
    /// Python event loop.
    ///
    /// We retrieve the Python context object, if setup by the user calling [PyApp::context] method,
    /// generate the [PyState] structure and build the [aws_smithy_http_server::Router], filling
    /// it with the functions generated by `PythonServerOperationHandlerGenerator.kt`.
@@ -198,10 +200,18 @@ impl PyApp {
        worker_number: isize,
    ) -> PyResult<()> {
        // Setup the Python asyncio loop to use `uvloop`.
        // If uvloop is not available as a dependency, the standard Python
        // event loop will be used instead.
        let asyncio = py.import("asyncio")?;
        let uvloop = py.import("uvloop")?;
        match py.import("uvloop") {
            Ok(uvloop) => {
                uvloop.call_method0("install")?;
                tracing::debug!("Setting up uvloop for current process");
            }
            Err(_) => {
                tracing::warn!("Uvloop not found, using Python standard event loop, which could have worse performance than uvloop");
            }
        }
        let event_loop = asyncio.call_method0("new_event_loop")?;
        asyncio.call_method1("set_event_loop", (event_loop,))?;
        // Create the `PyState` object from the Python context object.
@@ -309,6 +319,16 @@ impl PyApp {
        let mp = py.import("multiprocessing")?;
        // https://github.com/python/cpython/blob/f4c03484da59049eb62a9bf7777b963e2267d187/Lib/multiprocessing/context.py#L164
        mp.call_method0("allow_connection_pickling")?;

        // Starting from Python 3.8, on macOS, the spawn start method is now the default. See bpo-33725.
        // This forces the `PyApp` class to be pickled when it is shared between different process,
        // which is currently not supported by PyO3 classes.
        //
        // Forcing the multiprocessing start method to fork is a workaround for it.
        // https://github.com/pytest-dev/pytest-flask/issues/104#issuecomment-577908228
        #[cfg(target_os = "macos")]
        mp.call_method1("set_start_method", ("fork",))?;

        let address = address.unwrap_or_else(|| String::from("127.0.0.1"));
        let port = port.unwrap_or(13734);
        let socket = PySocket::new(address, port, backlog)?;