Skip to content

Cross-platform builds

Many modern Python packages include compiled extensions written in Rust or C/C++ for performance reasons. These compiled components are platform-specific and can cause deployment issues when building on different architectures.

Architecture Mismatch Issues

Building AWS Lambda packages on macOS (ARM64/Intel) for deployment on AWS Lambda (Linux x86_64 or ARM64) will result in incompatible binary dependencies that cause import errors at runtime.

Common compiled libraries

Taking into consideration Powertools for AWS dependencies and common Python packages, these libraries include compiled Rust/C components that require architecture-specific builds:

Library Language Components Impact Used in Powertools for AWS
pydantic Rust Core validation engine High - Core functionality affected ✅ Core dependency
aws-encryption-sdk C Encryption/decryption High - Data masking fails ✅ Optional (datamasking extra)
protobuf C++ Protocol buffer serialization High - Message parsing fails ✅ Optional (kafka-consumer-protobuf)
redis C Redis client with hiredis Medium - Falls back to pure Python ✅ Optional (redis extra)
valkey-glide Rust High-performance Redis client High - Client completely broken ✅ Optional (valkey extra)
orjson Rust JSON serialization Medium - Performance degradation ❌ Not used (but common)
uvloop C Event loop implementation Medium - Falls back to asyncio ❌ Not used (but common)
lxml C XML/HTML processing High - XML parsing fails ❌ Not used (but common)

Powertools extras dependencies and architecture

Different Powertools for AWS extras dependencies have varying levels of architecture dependency:

requirements.txt - Safe for any platform
1
2
3
4
5
6
# The 'all' extra includes both safe and architecture-dependent packages
aws-lambda-powertools[all]==3.18.0

# This is equivalent to:
# pydantic, pydantic-settings, aws-xray-sdk, fastjsonschema,
# aws-encryption-sdk, jsonpath-ng
requirements.txt - Requires Linux builds
1
2
3
4
5
6
7
8
# These extras include compiled dependencies
aws-lambda-powertools[parser]==3.18.0           # pydantic (Rust)
aws-lambda-powertools[validation]==3.18.0       # fastjsonschema (C)
aws-lambda-powertools[datamasking]==3.18.0      # aws-encryption-sdk (C)
aws-lambda-powertools[redis]==3.18.0            # redis with hiredis (C)
aws-lambda-powertools[valkey]==3.18.0           # valkey-glide (Rust)
aws-lambda-powertools[kafka-consumer-avro]==3.18.0      # avro (C)
aws-lambda-powertools[kafka-consumer-protobuf]==3.18.0  # protobuf (C++)
requirements.txt - Requires careful platform handling
1
2
3
# These extras have minimal or no compiled dependencies
aws-lambda-powertools[tracer]==3.18.0      # aws-xray-sdk (mostly pure Python)
aws-lambda-powertools[aws-sdk]==3.18.0    # boto3 (pure Python)
Powertools for AWS build strategy
  1. Use [all] extra with Docker builds for maximum compatibility
  2. Use specific extras if you want to avoid certain compiled dependencies
  3. Test imports after building to catch architecture mismatches early

Understanding Python wheels

Python wheels are binary distribution packages that include compiled extensions. Lambda requires specific wheel types based on the target runtime architecture and GLIBC version.

Wheel naming convention

Wheels follow a specific naming pattern that indicates compatibility:

1
{package}-{version}-{python tag}-{abi tag}-{platform tag}.whl

Example breakdown:

1
2
3
4
5
6
pydantic-2.5.0-cp311-cp311-linux_x86_64.whl
│        │     │     │     └─ Platform: Linux x86_64
│        │     │     └─ ABI: CPython 3.11
│        │     └─ Python: CPython 3.11
│        └─ Version: 2.5.0
└─ Package: pydantic

Platform tags and Lambda compatibility

Platform Tag Description Lambda Compatibility
linux_x86_64 Linux 64-bit Intel/AMD ✅ Lambda x86_64
linux_aarch64 Linux 64-bit ARM ✅ Lambda arm64
macosx_* macOS (any version) ❌ Not compatible
win_* Windows (any version) ❌ Not compatible
any Pure Python, no compiled code ✅ All platforms

Source distributions vs wheels

Package Type Extension Compilation Lambda Recommendation
Wheel .whl Pre-compiled ✅ Preferred - faster, consistent
Source Distribution .tar.gz Compile during install ❌ Avoid - platform-dependent compilation

Why wheels matter for Lambda:

  • Consistent builds - Same binary across environments
  • Faster installs - No compilation step required
  • Predictable dependencies - Known system library requirements
  • Architecture safety - Platform-specific binaries

Lambda runtime environments

Lambda managed runtimes use specific Amazon Linux versions versions with fixed GLIBC versions. Packages built on development machines with newer GLIBC versions will fail at runtime with import errors. Each Python runtime version corresponds to a specific Amazon Linux base system that determines compatible system library versions.

Amazon Linux versions and GLIBC compatibility

Python Runtime Base System GLIBC Version Architecture Support
python3.9 Amazon Linux 2 2.26 x86_64, arm64
python3.10 Amazon Linux 2 2.26 x86_64, arm64
python3.11 Amazon Linux 2 2.26 x86_64, arm64
python3.12 Amazon Linux 2023 2.34 x86_64, arm64
python3.13 Amazon Linux 2023 2.34 x86_64, arm64
GLIBC Version Mismatch

Compiled libraries built on systems with newer GLIBC versions will fail on Lambda runtimes with older GLIBC versions. Ubuntu 24.04 (GLIBC 2.39) and Ubuntu 22.04 (GLIBC 2.35) are incompatible with Lambda python3.11 and earlier (GLIBC 2.26). Always use --platform flags or Docker with Lambda base images.

Manylinux compatibility tags

Python wheels use manylinux tags to indicate GLIBC compatibility. Understanding these tags helps you choose the right wheels for Lambda:

manylinux Tag GLIBC Version Lambda Compatibility Recommendation
manylinux1 2.5 ✅ All runtimes Legacy, limited package support
manylinux2010 2.12 ✅ All runtimes Good compatibility
manylinux2014 2.17 ✅ All runtimes Recommended for most packages
manylinux_2_17 2.17 ✅ All runtimes Modern standard
manylinux_2_24 2.24 ✅ All runtimes Good for newer packages
manylinux_2_28 2.28 ✅ python3.12+, ❌ python3.11- Use with caution
manylinux_2_34 2.34 ✅ python3.12+, ❌ python3.11- AL2023 only

Runtime-specific considerations

Amazon Linux 2 (python3.8 - python3.11)

Amazon Linux 2 is based on RHEL 7 and uses an older GLIBC version (2.26). This provides broad compatibility but may limit access to newer compiled features.

Characteristics:

  • GLIBC 2.26 - Compatible with most manylinux wheels
  • OpenSSL 1.0.2 - Legacy TLS support

Best practices:

1
2
3
4
5
#!/bin/bash
# Use Amazon Linux 2 base image for builds
docker run --rm -v "$PWD":/var/task \
    public.ecr.aws/lambda/python:3.11 \
    pip install -r requirements.txt -t /var/task/

Amazon Linux 2023 (python3.12+)

Amazon Linux 2023 is a modern, minimal Linux distribution with updated system libraries and better security.

Characteristics:

  • GLIBC 2.34 - Supports newer compiled libraries
  • OpenSSL 3.0 - Latest TLS and cryptographic features
  • Smaller footprint - Optimized for containers and serverless

Migration considerations:

1
2
3
4
5
6
7
8
9
#!/bin/bash
# Some packages may require rebuilding for AL2023
# Check for GLIBC symbol errors in logs:
# ImportError: /lib64/libc.so.6: version `GLIBC_2.34' not found

# Use AL2023 base image for python3.12+
docker run --rm -v "$PWD":/var/task \
    public.ecr.aws/lambda/python:3.12 \
    pip install -r requirements.txt -t /var/task/

Multi-platform build strategies

Use AWS Lambda base images to ensure Linux x86_64 or ARM64 compatibility:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#Public Lambda image
FROM public.ecr.aws/lambda/python@sha256:7e7f098baa11a527fbe59f33f4ed032a36b6e87b22ea73da1175522095885f74

# Set workdir file
WORKDIR /tmp/app

# Copy requirements first for better caching
COPY requirements.txt .

# Install dependencies in Lambda-compatible environment
RUN pip install -r requirements.txt

# Copy application code
COPY . .

CMD ["app.lambda_handler"]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 #!/bin/bash

# Build using Lambda-compatible environment
docker build -f Dockerfile.lambda -t lambda-build .

# Extract built packages
docker create --name temp-container lambda-build
docker cp temp-container:/var/task ./build
docker rm temp-container

# Create deployment package
cd build && zip -r ../lambda-multiplatform.zip . && cd ..

echo "✅ Multi-platform compatible package created"

Force installation of Linux-compatible wheels:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

# Create build directory
mkdir -p build/

# Install Linux-compatible wheels
pip install \
    --platform manylinux2014_x86_64 \
    --target build/ \
    --implementation cp \
    --python-version 3.13 \
    --only-binary=:all: \
    --upgrade \
    --abi cp313 \
    -r requirements.txt

# Copy application code
cp -r src/* build/

# Create deployment package
cd build && zip -r ../lambda-linux.zip . && cd ..

echo "✅ Linux-compatible package created"

Use GitHub Actions with Linux runners for consistent builds:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
name: Build Lambda Package

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.13'

    - name: Install dependencies with Lambda-compatible wheels
      run: |
        # Force Linux x86_64 wheels compatible with Lambda GLIBC 2.34
        pip install --platform manylinux2014_x86_64 --only-binary=:all: \
          --python-version 3.13 --target build/ \
          -r requirements.txt

    - name: Copy application code
      run: cp -r src/* build/

    - name: Create deployment package
      run: |
        cd build && zip -r ../lambda-deployment.zip . && cd ..

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: lambda-package
        path: lambda-deployment.zip

  build-arm64:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.13'

    - name: Install dependencies for ARM64 Lambda
      run: |
        # Force Linux ARM64 wheels compatible with Lambda
        pip install --platform manylinux2014_aarch64 --only-binary=:all: \
          --python-version 3.13 --target build/ \
          -r requirements.txt

    - name: Copy application code
      run: cp -r src/* build/

    - name: Create deployment package
      run: |
        cd build && zip -r ../lambda-deployment-arm64.zip . && cd ..

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: lambda-package-arm64
        path: lambda-deployment-arm64.zip

Debugging compatibility issues

When you encounter runtime errors related to compiled dependencies, use these techniques to diagnose and fix the issues:

Common error patterns

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash
# Error message:
# ImportError: /lib64/libc.so.6: version `GLIBC_2.34' not found

# Check GLIBC version in Lambda runtime
ldd --version

# Check required GLIBC symbols in a library
objdump -T /opt/python/lib/python3.11/site-packages/pydantic/_internal/_pydantic_core.so | grep GLIBC

# Solution: Rebuild with compatible base image
docker run --rm -v "$PWD":/var/task public.ecr.aws/lambda/python:3.11 \
    pip install --force-reinstall pydantic -t /var/task/
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
# Error message:
# ImportError: cannot import name '_speedups' from 'pydantic'

# Check library architecture
file /opt/python/lib/python3.11/site-packages/pydantic/_internal/_pydantic_core.so

# Expected output for Lambda x86_64:
# ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked

# Solution: Force correct platform
pip install --platform manylinux2014_x86_64 --force-reinstall pydantic -t build/
1
2
3
4
5
6
7
8
9
#!/bin/bash
# Error message:
# ImportError: libffi.so.6: cannot open shared object file

# Check library dependencies
ldd /opt/python/lib/python3.11/site-packages/some_package/_extension.so

# Solution: Use Lambda base image with system dependencies
# Or switch to pure Python alternatives

Best practices for cross-platform builds

Development Workflow

Develop locally on your preferred platform, but always build deployment packages in a Linux environment or Docker container to ensure compatibility.

  1. Always build on Linux for Lambda deployments, or use Docker with Lambda base images
  2. Use --platform flags when installing with pip to force Linux-compatible wheels
  3. Test imports in your build environment before deployment
  4. Pin dependency versions to ensure reproducible builds across platforms
  5. Use CI/CD with Linux runners to avoid local architecture issues
  6. Consider Lambda container images for complex dependency scenarios