|
| 1 | +# reqwest-rs-labview |
| 2 | + |
| 3 | +A Rust FFI library that wraps the reqwest HTTP client for use in LabVIEW applications. It builds shared libraries (.dll, .so, .framework) that LabVIEW can call via the Call Library Function Node. |
| 4 | + |
| 5 | +**Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.** |
| 6 | + |
| 7 | +## Working Effectively |
| 8 | + |
| 9 | +### Bootstrap and Dependencies |
| 10 | +- **Install system dependencies on Linux**: |
| 11 | + ```bash |
| 12 | + sudo apt-get update -y |
| 13 | + sudo apt-get install -y pkg-config libssl-dev |
| 14 | + ``` |
| 15 | +- **Install Rust toolchain** (if not present): |
| 16 | + ```bash |
| 17 | + curl --proto '=https' --tlsv1.2 -sSf https://rustup.rs/sh.sh | sh |
| 18 | + source ~/.cargo/env |
| 19 | + ``` |
| 20 | +- **Install build tools**: |
| 21 | + ```bash |
| 22 | + cargo install just # Task runner for build scripts |
| 23 | + pip3 install ziglang # Required for cross-compilation |
| 24 | + cargo install cargo-zigbuild # Cross-compilation tool |
| 25 | + ``` |
| 26 | + |
| 27 | +### Build Commands |
| 28 | +- **Build for local platform** (release mode): |
| 29 | + ```bash |
| 30 | + cargo build --release |
| 31 | + # Output: target/release/libreqwest_dll.so (Linux) |
| 32 | + # Takes 2-3 minutes. NEVER CANCEL. Set timeout to 5+ minutes. |
| 33 | + ``` |
| 34 | +- **Debug build** (faster compilation, larger binary): |
| 35 | + ```bash |
| 36 | + cargo build |
| 37 | + # Output: target/debug/libreqwest_dll.so (Linux) |
| 38 | + # Takes ~20 seconds. Use for development/testing. |
| 39 | + ``` |
| 40 | +- **Cross-compile for Linux x86_64**: |
| 41 | + ```bash |
| 42 | + rustup target add x86_64-unknown-linux-gnu |
| 43 | + cargo zigbuild --target=x86_64-unknown-linux-gnu --release |
| 44 | + # Takes ~45 seconds. Set timeout to 2+ minutes. |
| 45 | + ``` |
| 46 | +- **Build for Windows** (requires Windows or cross-compilation setup): |
| 47 | + ```bash |
| 48 | + rustup target add i686-pc-windows-msvc x86_64-pc-windows-msvc |
| 49 | + cargo build --target=i686-pc-windows-msvc --release # 32-bit |
| 50 | + cargo build --target=x86_64-pc-windows-msvc --release # 64-bit |
| 51 | + ``` |
| 52 | + |
| 53 | +### Just Task Runner |
| 54 | +The repository includes a `justfile` with build automation: |
| 55 | +```bash |
| 56 | +just --list # Show available recipes |
| 57 | +``` |
| 58 | +**NOTE**: The justfile is designed for PowerShell on Windows. On Linux, use the direct cargo commands shown above instead. |
| 59 | + |
| 60 | +### Testing |
| 61 | +- **Run the test suite**: |
| 62 | + ```bash |
| 63 | + cargo test |
| 64 | + # Takes 1-2 minutes. NEVER CANCEL. Set timeout to 5+ minutes. |
| 65 | + # NOTE: Integration tests may fail in network-restricted environments due to httpbin.org dependencies |
| 66 | + ``` |
| 67 | +- **Run tests without network-dependent integration tests**: |
| 68 | + ```bash |
| 69 | + cargo test --lib |
| 70 | + ``` |
| 71 | + |
| 72 | +### Code Quality and Linting |
| 73 | +- **Format code** (ALWAYS run before committing): |
| 74 | + ```bash |
| 75 | + cargo fmt |
| 76 | + ``` |
| 77 | +- **Check formatting**: |
| 78 | + ```bash |
| 79 | + cargo fmt --check |
| 80 | + ``` |
| 81 | +- **Run linter** (expect FFI-related warnings - these are normal): |
| 82 | + ```bash |
| 83 | + cargo clippy --all-targets --all-features |
| 84 | + # NOTE: Clippy will show warnings about unsafe pointer operations in FFI code - these are expected and normal |
| 85 | + ``` |
| 86 | + |
| 87 | +## Validation Scenarios |
| 88 | + |
| 89 | +After making changes to the Rust code, ALWAYS: |
| 90 | + |
| 91 | +1. **Build successfully**: `cargo build --release` must complete without errors |
| 92 | +2. **Format code**: `cargo fmt` must run clean |
| 93 | +3. **Test core functionality**: Unit tests should pass (`cargo test --lib`) |
| 94 | +4. **Cross-compile test**: Verify cross-compilation still works with `cargo zigbuild` |
| 95 | +5. **Check library output**: Verify shared library is generated in `target/release/` |
| 96 | +6. **Validate FFI exports**: Check that required FFI functions are exported: |
| 97 | + ```bash |
| 98 | + nm -D target/release/libreqwest_dll.so | grep -E "client_|request_|headers_" | head -5 |
| 99 | + # Should show exported C functions like client_builder_create, etc. |
| 100 | + ``` |
| 101 | + |
| 102 | +### Complete User Scenario Testing |
| 103 | +ALWAYS test these complete scenarios after making changes: |
| 104 | + |
| 105 | +1. **Library Creation and Cleanup**: |
| 106 | + - Create a client builder with `client_builder_create()` |
| 107 | + - Configure it with timeout and other settings |
| 108 | + - Build a client with `client_builder_create_client_and_start()` |
| 109 | + - Clean up with `client_destroy()` and `client_builder_destroy()` |
| 110 | + |
| 111 | +2. **Request Building and Execution**: |
| 112 | + - Create a request builder from a client |
| 113 | + - Configure request headers, body, auth, etc. |
| 114 | + - Send request asynchronously |
| 115 | + - Monitor progress and read response |
| 116 | + - Clean up request resources |
| 117 | + |
| 118 | +3. **Header Management**: |
| 119 | + - Create header maps with `headers_create()` |
| 120 | + - Add multiple headers with `headers_add()` |
| 121 | + - Retrieve all headers with `headers_get_all()` |
| 122 | + - Clean up with `headers_destroy()` |
| 123 | + |
| 124 | +### Functional Validation Test |
| 125 | +Run this simple C program test to validate basic FFI functionality: |
| 126 | +```c |
| 127 | +// Save as test_ffi.c and compile with: gcc test_ffi.c -ldl -o test_ffi |
| 128 | +#include <stdio.h> |
| 129 | +#include <dlfcn.h> |
| 130 | + |
| 131 | +int main() { |
| 132 | + void *handle = dlopen("./target/release/libreqwest_dll.so", RTLD_LAZY); |
| 133 | + if (!handle) return 1; |
| 134 | + |
| 135 | + void* (*create)() = dlsym(handle, "client_builder_create"); |
| 136 | + void (*destroy)(void*) = dlsym(handle, "client_builder_destroy"); |
| 137 | + |
| 138 | + if (!create || !destroy) { dlclose(handle); return 1; } |
| 139 | + |
| 140 | + void* builder = create(); |
| 141 | + if (builder == NULL) { dlclose(handle); return 1; } |
| 142 | + |
| 143 | + printf("PASS: FFI functions working correctly\n"); |
| 144 | + destroy(builder); |
| 145 | + dlclose(handle); |
| 146 | + return 0; |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +### Manual Testing with LabVIEW (if available) |
| 151 | +- The built shared libraries are consumed by LabVIEW via the Call Library Function Node |
| 152 | +- LabVIEW code is in `lv_src/` directory with `.vi`, `.lvproj`, and `.lvlib` files |
| 153 | +- Pre-built libraries are included: `lv_reqwest_32.dll`, `lv_reqwest_64.dll`, `lv_reqwest_64.so`, `lv_reqwest_64.framework.zip` |
| 154 | +- Test VI: `lv_src/test_client.vi` can be used to validate functionality |
| 155 | +- Example VI: `lv_src/Examples/Example - Download with Progress and Abort (RUST).vi` demonstrates library usage |
| 156 | + |
| 157 | +## Repository Structure |
| 158 | + |
| 159 | +### Key Directories |
| 160 | +- `src/`: Rust source code for the FFI library |
| 161 | + - `ffi/`: C-compatible FFI function implementations |
| 162 | + - `lib.rs`: Main library entry point and exports |
| 163 | + - `types.rs`: Rust type definitions used in FFI |
| 164 | + - `globals.rs`: Global state management for async operations |
| 165 | +- `lv_src/`: LabVIEW source code and pre-built libraries |
| 166 | +- `tests/`: Integration tests (require network access) |
| 167 | +- `docs/`: Developer and user documentation |
| 168 | + |
| 169 | +### Important Files |
| 170 | +- `Cargo.toml`: Rust project configuration - builds as both `cdylib` and `rlib` |
| 171 | +- `justfile`: Build automation (PowerShell-based, designed for Windows) |
| 172 | +- `.github/workflows/rust.yml`: CI/CD pipeline for building multi-platform libraries |
| 173 | +- `mac_build.sh` & `bundle_framework.sh`: macOS-specific build scripts |
| 174 | + |
| 175 | +## Common Tasks |
| 176 | + |
| 177 | +### Building Multi-Platform Libraries |
| 178 | +The repository supports building for multiple platforms: |
| 179 | +- **Windows**: i686 and x86_64 (32-bit and 64-bit .dll files) |
| 180 | +- **Linux**: x86_64 (.so file) |
| 181 | +- **macOS**: x86_64 and aarch64 (.framework bundle) |
| 182 | + |
| 183 | +### Cross-Platform Build Process |
| 184 | +1. **CI Pipeline**: Uses GitHub Actions with matrix builds on ubuntu-latest, windows-latest, macos-latest |
| 185 | +2. **Local Development**: Use `cargo zigbuild` for cross-compilation on Linux |
| 186 | +3. **Output Naming**: Libraries are renamed to `lv_reqwest_[32|64].[dll|so]` format |
| 187 | + |
| 188 | +### Working with FFI Code |
| 189 | +- **Memory Management**: Follows strict "creator destroys" pattern - if you create it, you must destroy it |
| 190 | +- **String Handling**: Uses C-style strings (CString/CStr) for LabVIEW compatibility |
| 191 | +- **Error Handling**: Two-tier system - configuration errors vs transport errors |
| 192 | +- **Async Operations**: Built on tokio runtime, hidden from LabVIEW callers |
| 193 | +- **Thread Safety**: Global runtime and thread-safe data structures manage concurrent operations |
| 194 | +- **Pointer Safety**: FFI functions use unsafe pointer operations - clippy warnings are expected and normal |
| 195 | + |
| 196 | +### Common Development Workflows |
| 197 | + |
| 198 | +#### Adding a new FFI function: |
| 199 | +1. Add function signature to appropriate module in `src/ffi/` |
| 200 | +2. Add `#[unsafe(no_mangle)]` and `pub extern "C"` decorators |
| 201 | +3. Add to exports in `src/lib.rs` |
| 202 | +4. Build and test: `cargo build --release && cargo test --lib` |
| 203 | +5. Format: `cargo fmt` |
| 204 | +6. Validate FFI export: `nm -D target/release/libreqwest_dll.so | grep your_function` |
| 205 | + |
| 206 | +#### Modifying existing functionality: |
| 207 | +1. Make minimal changes to Rust code |
| 208 | +2. Build: `cargo build --release` |
| 209 | +3. Run validation tests (see Validation Scenarios section) |
| 210 | +4. Update corresponding LabVIEW VIs if FFI signatures changed |
| 211 | +5. Format: `cargo fmt` |
| 212 | + |
| 213 | +## Troubleshooting |
| 214 | + |
| 215 | +### Common Build Issues |
| 216 | +- **SSL/TLS errors**: Ensure `pkg-config` and `libssl-dev` are installed on Linux |
| 217 | +- **Cross-compilation failures**: Verify `ziglang` and `cargo-zigbuild` are properly installed |
| 218 | +- **Test failures**: Integration tests require internet access - use `cargo test --lib` for offline testing |
| 219 | + |
| 220 | +### Development Tips |
| 221 | +- **FFI Safety**: Be careful with pointer operations - the existing clippy warnings are expected for FFI code |
| 222 | +- **Async Runtime**: The library manages a global tokio runtime - don't create additional runtimes |
| 223 | +- **LabVIEW Integration**: Changes to FFI signatures require updates to corresponding LabVIEW VIs |
| 224 | +- **Platform Testing**: Test library loading in LabVIEW on target platform when possible |
| 225 | + |
| 226 | +### Build Time Expectations |
| 227 | +- **Initial clean build (release)**: 2-3 minutes (downloads and compiles all dependencies) |
| 228 | +- **Initial clean build (debug)**: 15-20 seconds (much faster, unoptimized) |
| 229 | +- **Incremental builds**: 2-10 seconds for small changes |
| 230 | +- **Cross-compilation (initial)**: ~45 seconds after dependencies are built |
| 231 | +- **Cross-compilation (incremental)**: ~10 seconds for small changes |
| 232 | +- **Test suite**: 1-2 minutes (longer in network-restricted environments) |
| 233 | +- **Unit tests only**: ~2 seconds (use `cargo test --lib`) |
| 234 | +- **Formatting**: < 1 second (`cargo fmt`) |
| 235 | +- **Clippy linting**: 20-30 seconds for full check |
| 236 | + |
| 237 | +**CRITICAL TIMING NOTES:** |
| 238 | +- NEVER CANCEL builds or tests that appear to hang - Rust compilation can take several minutes |
| 239 | +- Always set timeouts to 5+ minutes for `cargo build --release` (first build) |
| 240 | +- Set timeouts to 1+ minutes for `cargo build` (debug builds) |
| 241 | +- Set timeouts to 2+ minutes for `cargo zigbuild` (first cross-compile) |
| 242 | +- Set timeouts to 5+ minutes for `cargo test` (includes network-dependent integration tests) |
| 243 | +- Set timeouts to 1+ minutes for `cargo clippy --all-targets --all-features` |
0 commit comments