├── .github └── workflows │ ├── build.yml │ ├── setup-vitasdk.yml │ └── update-bindings.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── build-util ├── Cargo.toml └── src │ ├── bindgen.rs │ ├── lib.rs │ ├── main.rs │ ├── visitors.rs │ └── vita_headers_db.rs ├── build.rs ├── headers ├── all.h └── time.h ├── rust-toolchain.toml └── src ├── bindings.rs ├── lib.rs └── tests ├── mod.rs └── sce_clib.rs /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | env: 10 | # If you update LLVM_VERSION, remember to also update `update-bindings.yml` 11 | # and `README.md` 12 | LLVM_VERSION: "16" 13 | 14 | jobs: 15 | install-vitasdk: 16 | uses: ./.github/workflows/setup-vitasdk.yml 17 | with: 18 | path: /opt/vitasdk 19 | 20 | build-tests: 21 | name: Build tests 22 | runs-on: ubuntu-latest 23 | needs: install-vitasdk 24 | timeout-minutes: 20 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - name: Restore vitasdk cache 29 | uses: actions/cache/restore@v4 30 | with: 31 | path: /opt/vitasdk 32 | key: ${{ runner.os }}-vitasdk 33 | fail-on-cache-miss: true 34 | 35 | - name: Cache dependencies 36 | uses: actions/cache@v4 37 | with: 38 | path: | 39 | ~/.cargo/bin/ 40 | ~/.cargo/registry/index/ 41 | ~/.cargo/registry/cache/ 42 | ~/.cargo/git/db/ 43 | key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} 44 | 45 | - name: Install cargo-vita 46 | continue-on-error: true 47 | run: | 48 | cargo install cargo-vita 49 | 50 | - name: Install rust nightly 51 | uses: actions-rs/toolchain@v1 52 | with: 53 | toolchain: nightly 54 | profile: minimal 55 | components: rust-src 56 | 57 | - name: Add Vita SDK tools to path 58 | run: | 59 | echo "/opt/vitasdk/bin" >> $GITHUB_PATH 60 | 61 | - name: Build tests in debug mode 62 | env: 63 | VITASDK: /opt/vitasdk 64 | run: | 65 | cargo +nightly vita build --default-title-id SYSTEST01 vpk -- --tests --features SceLibKernel_stub 66 | 67 | - name: Build tests in release mode 68 | env: 69 | VITASDK: /opt/vitasdk 70 | run: | 71 | cargo +nightly vita build --default-title-id SYSTEST01 vpk -- --tests --release --features SceLibKernel_stub 72 | 73 | - name: Upload debug build 74 | uses: actions/upload-artifact@v4 75 | with: 76 | name: std-hello-world-debug-build 77 | path: target/armv7-sony-vita-newlibeabihf/debug/deps/vitasdk_sys-*.* 78 | if-no-files-found: error 79 | 80 | - name: Upload release build 81 | uses: actions/upload-artifact@v4 82 | with: 83 | name: std-hello-world-release-build 84 | path: target/armv7-sony-vita-newlibeabihf/release/deps/vitasdk_sys-*.* 85 | if-no-files-found: error 86 | 87 | clippy: 88 | name: Clippy 89 | runs-on: ubuntu-latest 90 | needs: install-vitasdk 91 | timeout-minutes: 10 92 | steps: 93 | - uses: actions/checkout@v4 94 | 95 | - name: Restore vitasdk cache 96 | uses: actions/cache/restore@v4 97 | with: 98 | path: /opt/vitasdk 99 | key: ${{ runner.os }}-vitasdk 100 | fail-on-cache-miss: true 101 | 102 | - uses: actions-rs/toolchain@v1 103 | with: 104 | toolchain: stable 105 | components: clippy 106 | profile: minimal 107 | override: true 108 | 109 | - name: Run clippy 110 | env: 111 | VITASDK: /opt/vitasdk 112 | run: | 113 | cargo clippy --tests --workspace --features all-stubs -- -Dclippy::all -Dwarnings 114 | 115 | rustfmt: 116 | name: Rustfmt 117 | runs-on: ubuntu-latest 118 | timeout-minutes: 10 119 | steps: 120 | - uses: actions/checkout@v4 121 | 122 | - uses: actions-rs/toolchain@v1 123 | with: 124 | toolchain: stable 125 | components: rustfmt 126 | profile: minimal 127 | override: true 128 | 129 | - name: Run rustfmt 130 | run: | 131 | cargo fmt --check --all 132 | 133 | missing-libs: 134 | name: Check missing libs 135 | runs-on: ubuntu-latest 136 | needs: install-vitasdk 137 | timeout-minutes: 10 138 | steps: 139 | - uses: actions/checkout@v4 140 | with: 141 | submodules: true 142 | 143 | - name: Restore vitasdk cache 144 | uses: actions/cache/restore@v4 145 | with: 146 | path: /opt/vitasdk 147 | key: ${{ runner.os }}-vitasdk 148 | fail-on-cache-miss: true 149 | 150 | - name: Cache LLVM and Clang 151 | id: cache-llvm 152 | uses: actions/cache@v4 153 | with: 154 | path: | 155 | ${{ runner.temp }}/llvm 156 | key: llvm 157 | 158 | - name: Install LLVM and Clang 159 | uses: KyleMayes/install-llvm-action@v2 160 | with: 161 | version: ${{ env.LLVM_VERSION }} 162 | directory: ${{ runner.temp }}/llvm 163 | cached: ${{ steps.cache-llvm.outputs.cache-hit }} 164 | 165 | - uses: actions-rs/toolchain@v1 166 | with: 167 | toolchain: stable 168 | profile: minimal 169 | override: true 170 | 171 | - name: Run build-util 172 | env: 173 | VITASDK: /opt/vitasdk 174 | run: | 175 | cargo run --profile build-util -p vitasdk-sys-build-util -- stub-libs --missing-libs --fail-if-any 176 | 177 | # Checks if there's no diff when regenerating bindings 178 | check-bindings: 179 | name: Check bindings 180 | runs-on: ubuntu-latest 181 | needs: install-vitasdk 182 | timeout-minutes: 10 183 | steps: 184 | - uses: actions/checkout@v4 185 | with: 186 | submodules: true 187 | - name: Restore vitasdk cache 188 | uses: actions/cache/restore@v4 189 | with: 190 | path: /opt/vitasdk 191 | key: ${{ runner.os }}-vitasdk 192 | fail-on-cache-miss: true 193 | 194 | - name: Cache LLVM and Clang 195 | id: cache-llvm 196 | uses: actions/cache@v4 197 | with: 198 | path: | 199 | ${{ runner.temp }}/llvm 200 | key: llvm 201 | 202 | - name: Install LLVM and Clang 203 | uses: KyleMayes/install-llvm-action@v2 204 | with: 205 | version: ${{ env.LLVM_VERSION }} 206 | directory: ${{ runner.temp }}/llvm 207 | cached: ${{ steps.cache-llvm.outputs.cache-hit }} 208 | 209 | - uses: actions-rs/toolchain@v1 210 | with: 211 | toolchain: stable 212 | profile: minimal 213 | override: true 214 | 215 | - name: Regenerate bindings 216 | env: 217 | VITASDK: /opt/vitasdk 218 | # From clang-sys 219 | LIBCLANG_PATH: ${{ runner.temp }}/llvm/lib 220 | LLVM_CONFIG_PATH: ${{ runner.temp }}/llvm/bin/llvm-config 221 | run: | 222 | cargo run --profile build-util -p vitasdk-sys-build-util -- bindgen 223 | 224 | - name: Check diff 225 | run: | 226 | git add . && git diff --quiet && git diff --cached --quiet 227 | 228 | doc: 229 | name: Doc 230 | runs-on: ubuntu-latest 231 | timeout-minutes: 30 232 | env: 233 | RUSTDOCFLAGS: -D warnings 234 | steps: 235 | - uses: actions/checkout@v4 236 | 237 | - uses: actions-rs/toolchain@v1 238 | with: 239 | toolchain: nightly 240 | components: rust-docs, rust-src 241 | profile: minimal 242 | override: true 243 | 244 | - name: Run cargo doc 245 | run: DOCS_RS=1 RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --features all-stubs,log-build,vitasdk-utils --target armv7-sony-vita-newlibeabihf -Z build-std 246 | -------------------------------------------------------------------------------- /.github/workflows/setup-vitasdk.yml: -------------------------------------------------------------------------------- 1 | name: Setup Vita SDK 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | path: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | # This job is also on update-bindings.yml. If you 12 | install-vitasdk: 13 | name: Install Vita SDK 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Cache vitasdk 17 | id: cache 18 | uses: actions/cache@v4 19 | with: 20 | path: ${{ inputs.path }} 21 | # Don't really know a good key to use here, but the cache will be 22 | # deleted automatically if it's not used for a week. 23 | key: ${{ runner.os }}-vitasdk 24 | 25 | - name: Checkout VPDM 26 | uses: actions/checkout@v4 27 | with: 28 | repository: vitasdk/vdpm 29 | 30 | - name: Install 31 | if: steps.cache.outputs.cache-hit != 'true' 32 | env: 33 | VITASDK: ${{ inputs.path }} 34 | run: | 35 | ./bootstrap-vitasdk.sh 36 | ./install-all.sh 37 | -------------------------------------------------------------------------------- /.github/workflows/update-bindings.yml: -------------------------------------------------------------------------------- 1 | name: Create PR to update bindings 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0 2 5 *' 7 | 8 | env: 9 | PR_BRANCH: update-bindings 10 | # If you update LLVM_VERSION, remember to also update `build.yml` and 11 | # `README.md` 12 | LLVM_VERSION: "16" 13 | 14 | jobs: 15 | install-vitasdk: 16 | uses: ./.github/workflows/setup-vitasdk.yml 17 | with: 18 | path: /opt/vitasdk 19 | 20 | update-and-regenrate: 21 | name: Update and regenerate 22 | runs-on: ubuntu-latest 23 | needs: install-vitasdk 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | submodules: true 28 | 29 | - name: Restore vitasdk cache 30 | uses: actions/cache/restore@v4 31 | with: 32 | path: /opt/vitasdk 33 | key: ${{ runner.os }}-vitasdk 34 | fail-on-cache-miss: true 35 | 36 | - name: Cache LLVM and Clang 37 | id: cache-llvm 38 | uses: actions/cache@v4 39 | with: 40 | path: | 41 | ${{ runner.temp }}/llvm 42 | key: llvm 43 | 44 | - name: Install LLVM and Clang 45 | uses: KyleMayes/install-llvm-action@v2 46 | with: 47 | version: ${{ env.LLVM_VERSION }} 48 | directory: ${{ runner.temp }}/llvm 49 | cached: ${{ steps.cache-llvm.outputs.cache-hit }} 50 | 51 | - name: Cache build-util dependencies 52 | uses: actions/cache@v4 53 | with: 54 | path: | 55 | ~/.cargo/bin/ 56 | ~/.cargo/registry/index/ 57 | ~/.cargo/registry/cache/ 58 | ~/.cargo/git/db/ 59 | target/ 60 | key: ${{ runner.os }}-cargo-build-util-${{ hashFiles('Cargo.lock') }} 61 | 62 | - name: Update vita-headers 63 | run: | 64 | git submodule update --recursive --remote vita-headers 65 | echo "VITA_HEADERS_HASH=$(git submodule status | grep vita-headers | cut -d ' ' -f 2)" >> $GITHUB_ENV 66 | 67 | - uses: actions-rs/toolchain@v1 68 | with: 69 | toolchain: stable 70 | components: rustfmt 71 | profile: minimal 72 | override: true 73 | 74 | - name: Regenerate bindings 75 | env: 76 | VITASDK: /opt/vitasdk 77 | # From clang-sys 78 | LIBCLANG_PATH: ${{ runner.temp }}/llvm/lib 79 | LLVM_CONFIG_PATH: ${{ runner.temp }}/llvm/bin/llvm-config 80 | run: | 81 | cargo run --profile build-util -p vitasdk-sys-build-util -- bindgen 82 | 83 | - name: Generate GitHub token 84 | uses: actions/create-github-app-token@v1 85 | id: generate-token 86 | with: 87 | app-id: ${{ secrets.APP_ID }} 88 | private-key: ${{ secrets.APP_PRIVATE_KEY }} 89 | 90 | - name: Commit and create pull request 91 | id: create-pull-request 92 | uses: peter-evans/create-pull-request@v7 93 | with: 94 | token: ${{ steps.generate-token.outputs.token }} 95 | title: Update vita-headers bindings 96 | body: Created by the action at [.github/workflows/update-bindings.yml](../tree/main/.github/workflows/update-bindings.yml) 97 | branch: ${{ env.PR_BRANCH }} 98 | delete-branch: true 99 | commit-message: Update vita-headers to ${{ env.VITA_HEADERS_HASH }} 100 | assignees: pheki,ZetaNumbers 101 | committer: Aphek 102 | author: Aphek 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vita-headers"] 2 | path = vita-headers 3 | url = https://github.com/vitasdk/vita-headers.git 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Common Changelog](https://common-changelog.org/) and [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). 4 | 5 | ## [0.3.3] - 2024-02-25 6 | 7 | ### Changed 8 | 9 | - Bindings are now pre-generated by default, meaning that LLVM / Clang is no longer requried to be installed (#21, #24). 10 | - There's a new `bindgen` feature which makes the crate generate bindings at compile-time by using headers at `$VITASDK` instead of using pre-generated bindings (#21). 11 | - Simplified CI by using vita-rust-bot to create PRs (#23). 12 | 13 | ## [0.3.2] - 2023-10-06 14 | 15 | ### Fixed 16 | 17 | - Fixed spurious build script reruns (#18). 18 | 19 | ## [0.3.1] - 2023-10-03 20 | 21 | ### Fixed 22 | 23 | - Fixed build script on docs.rs and possibly other environments by enabling include path detection (#15). 24 | 25 | ## [0.3.0] - 2023-09-29 26 | 27 | _This release includes a rewrite of the whole binding generation process by @ZetaNumbers._ 28 | 29 | ### Changed 30 | 31 | - **Breaking** The bindings are now generated on a flat structure, so now all items are defined at the root of the crate. 32 | - **Breaking** Items are now defined based on features, each feature corresponding to a stub file. Enabling the feature will cause the required stub to be linked. 33 | - **Breaking** Bindings are now generated at build-time, so [bindgen's requirements](https://rust-lang.github.io/rust-bindgen/requirements.html) need to be installed. 34 | - Improvements to CI, including new checks for docs (which uploads generated docs as an artifact). 35 | 36 | ## [0.2.0] - 2023-09-12 37 | 38 | ### Changed 39 | 40 | - **Breaking:** Stopped generating duplicated struct definitions. A way to add missing imports was added to `generator`. 41 | - **Breaking:** Update vita-headers to 251fb0ba8506766cf8bee4e330e88e2f934b175b (they are moving things a lot, so paths may need to be updated) 42 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.13" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "utf8parse", 26 | ] 27 | 28 | [[package]] 29 | name = "anstyle" 30 | version = "1.0.6" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" 33 | 34 | [[package]] 35 | name = "anstyle-parse" 36 | version = "0.2.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 39 | dependencies = [ 40 | "utf8parse", 41 | ] 42 | 43 | [[package]] 44 | name = "anstyle-query" 45 | version = "1.0.2" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 48 | dependencies = [ 49 | "windows-sys", 50 | ] 51 | 52 | [[package]] 53 | name = "anstyle-wincon" 54 | version = "3.0.2" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 57 | dependencies = [ 58 | "anstyle", 59 | "windows-sys", 60 | ] 61 | 62 | [[package]] 63 | name = "bindgen" 64 | version = "0.69.4" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" 67 | dependencies = [ 68 | "bitflags", 69 | "cexpr", 70 | "clang-sys", 71 | "itertools", 72 | "lazy_static", 73 | "lazycell", 74 | "log", 75 | "prettyplease", 76 | "proc-macro2", 77 | "quote", 78 | "regex", 79 | "rustc-hash", 80 | "shlex", 81 | "syn", 82 | "which", 83 | ] 84 | 85 | [[package]] 86 | name = "bitflags" 87 | version = "2.4.2" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" 90 | 91 | [[package]] 92 | name = "cexpr" 93 | version = "0.6.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 96 | dependencies = [ 97 | "nom", 98 | ] 99 | 100 | [[package]] 101 | name = "cfg-if" 102 | version = "1.0.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 105 | 106 | [[package]] 107 | name = "clang-sys" 108 | version = "1.7.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" 111 | dependencies = [ 112 | "glob", 113 | "libc", 114 | "libloading", 115 | ] 116 | 117 | [[package]] 118 | name = "colorchoice" 119 | version = "1.0.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 122 | 123 | [[package]] 124 | name = "either" 125 | version = "1.10.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" 128 | 129 | [[package]] 130 | name = "env_filter" 131 | version = "0.1.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" 134 | dependencies = [ 135 | "log", 136 | "regex", 137 | ] 138 | 139 | [[package]] 140 | name = "env_logger" 141 | version = "0.11.3" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" 144 | dependencies = [ 145 | "anstream", 146 | "anstyle", 147 | "env_filter", 148 | "humantime", 149 | "log", 150 | ] 151 | 152 | [[package]] 153 | name = "equivalent" 154 | version = "1.0.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 157 | 158 | [[package]] 159 | name = "errno" 160 | version = "0.3.8" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 163 | dependencies = [ 164 | "libc", 165 | "windows-sys", 166 | ] 167 | 168 | [[package]] 169 | name = "glob" 170 | version = "0.3.1" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 173 | 174 | [[package]] 175 | name = "hashbrown" 176 | version = "0.14.3" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 179 | 180 | [[package]] 181 | name = "home" 182 | version = "0.5.9" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 185 | dependencies = [ 186 | "windows-sys", 187 | ] 188 | 189 | [[package]] 190 | name = "humantime" 191 | version = "2.1.0" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 194 | 195 | [[package]] 196 | name = "indexmap" 197 | version = "2.2.5" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" 200 | dependencies = [ 201 | "equivalent", 202 | "hashbrown", 203 | ] 204 | 205 | [[package]] 206 | name = "itertools" 207 | version = "0.12.1" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 210 | dependencies = [ 211 | "either", 212 | ] 213 | 214 | [[package]] 215 | name = "itoa" 216 | version = "1.0.10" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 219 | 220 | [[package]] 221 | name = "lazy_static" 222 | version = "1.4.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 225 | 226 | [[package]] 227 | name = "lazycell" 228 | version = "1.3.0" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 231 | 232 | [[package]] 233 | name = "libc" 234 | version = "0.2.153" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 237 | 238 | [[package]] 239 | name = "libloading" 240 | version = "0.8.3" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" 243 | dependencies = [ 244 | "cfg-if", 245 | "windows-targets", 246 | ] 247 | 248 | [[package]] 249 | name = "linux-raw-sys" 250 | version = "0.4.13" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 253 | 254 | [[package]] 255 | name = "log" 256 | version = "0.4.21" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 259 | 260 | [[package]] 261 | name = "memchr" 262 | version = "2.7.1" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 265 | 266 | [[package]] 267 | name = "minimal-lexical" 268 | version = "0.2.1" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 271 | 272 | [[package]] 273 | name = "nom" 274 | version = "7.1.3" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 277 | dependencies = [ 278 | "memchr", 279 | "minimal-lexical", 280 | ] 281 | 282 | [[package]] 283 | name = "once_cell" 284 | version = "1.19.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 287 | 288 | [[package]] 289 | name = "prettyplease" 290 | version = "0.2.16" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" 293 | dependencies = [ 294 | "proc-macro2", 295 | "syn", 296 | ] 297 | 298 | [[package]] 299 | name = "proc-macro2" 300 | version = "1.0.78" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 303 | dependencies = [ 304 | "unicode-ident", 305 | ] 306 | 307 | [[package]] 308 | name = "quote" 309 | version = "1.0.35" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 312 | dependencies = [ 313 | "proc-macro2", 314 | ] 315 | 316 | [[package]] 317 | name = "regex" 318 | version = "1.10.3" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" 321 | dependencies = [ 322 | "aho-corasick", 323 | "memchr", 324 | "regex-automata", 325 | "regex-syntax", 326 | ] 327 | 328 | [[package]] 329 | name = "regex-automata" 330 | version = "0.4.6" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 333 | dependencies = [ 334 | "aho-corasick", 335 | "memchr", 336 | "regex-syntax", 337 | ] 338 | 339 | [[package]] 340 | name = "regex-syntax" 341 | version = "0.8.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 344 | 345 | [[package]] 346 | name = "rustc-hash" 347 | version = "1.1.0" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 350 | 351 | [[package]] 352 | name = "rustix" 353 | version = "0.38.31" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" 356 | dependencies = [ 357 | "bitflags", 358 | "errno", 359 | "libc", 360 | "linux-raw-sys", 361 | "windows-sys", 362 | ] 363 | 364 | [[package]] 365 | name = "ryu" 366 | version = "1.0.17" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 369 | 370 | [[package]] 371 | name = "serde" 372 | version = "1.0.197" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 375 | dependencies = [ 376 | "serde_derive", 377 | ] 378 | 379 | [[package]] 380 | name = "serde_derive" 381 | version = "1.0.197" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 384 | dependencies = [ 385 | "proc-macro2", 386 | "quote", 387 | "syn", 388 | ] 389 | 390 | [[package]] 391 | name = "serde_spanned" 392 | version = "0.6.5" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" 395 | dependencies = [ 396 | "serde", 397 | ] 398 | 399 | [[package]] 400 | name = "serde_yaml" 401 | version = "0.9.32" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" 404 | dependencies = [ 405 | "indexmap", 406 | "itoa", 407 | "ryu", 408 | "serde", 409 | "unsafe-libyaml", 410 | ] 411 | 412 | [[package]] 413 | name = "shlex" 414 | version = "1.3.0" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 417 | 418 | [[package]] 419 | name = "syn" 420 | version = "2.0.52" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" 423 | dependencies = [ 424 | "proc-macro2", 425 | "quote", 426 | "unicode-ident", 427 | ] 428 | 429 | [[package]] 430 | name = "toml" 431 | version = "0.8.10" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" 434 | dependencies = [ 435 | "serde", 436 | "serde_spanned", 437 | "toml_datetime", 438 | "toml_edit", 439 | ] 440 | 441 | [[package]] 442 | name = "toml_datetime" 443 | version = "0.6.5" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" 446 | dependencies = [ 447 | "serde", 448 | ] 449 | 450 | [[package]] 451 | name = "toml_edit" 452 | version = "0.22.6" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" 455 | dependencies = [ 456 | "indexmap", 457 | "serde", 458 | "serde_spanned", 459 | "toml_datetime", 460 | "winnow", 461 | ] 462 | 463 | [[package]] 464 | name = "unicode-ident" 465 | version = "1.0.12" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 468 | 469 | [[package]] 470 | name = "unsafe-libyaml" 471 | version = "0.2.10" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" 474 | 475 | [[package]] 476 | name = "utf8parse" 477 | version = "0.2.1" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 480 | 481 | [[package]] 482 | name = "vitasdk-sys" 483 | version = "0.3.3" 484 | dependencies = [ 485 | "env_logger", 486 | "vitasdk-sys-build-util", 487 | ] 488 | 489 | [[package]] 490 | name = "vitasdk-sys-build-util" 491 | version = "0.2.0" 492 | dependencies = [ 493 | "bindgen", 494 | "env_logger", 495 | "log", 496 | "proc-macro2", 497 | "quote", 498 | "serde", 499 | "serde_yaml", 500 | "syn", 501 | "toml", 502 | ] 503 | 504 | [[package]] 505 | name = "which" 506 | version = "4.4.2" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 509 | dependencies = [ 510 | "either", 511 | "home", 512 | "once_cell", 513 | "rustix", 514 | ] 515 | 516 | [[package]] 517 | name = "windows-sys" 518 | version = "0.52.0" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 521 | dependencies = [ 522 | "windows-targets", 523 | ] 524 | 525 | [[package]] 526 | name = "windows-targets" 527 | version = "0.52.4" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 530 | dependencies = [ 531 | "windows_aarch64_gnullvm", 532 | "windows_aarch64_msvc", 533 | "windows_i686_gnu", 534 | "windows_i686_msvc", 535 | "windows_x86_64_gnu", 536 | "windows_x86_64_gnullvm", 537 | "windows_x86_64_msvc", 538 | ] 539 | 540 | [[package]] 541 | name = "windows_aarch64_gnullvm" 542 | version = "0.52.4" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 545 | 546 | [[package]] 547 | name = "windows_aarch64_msvc" 548 | version = "0.52.4" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 551 | 552 | [[package]] 553 | name = "windows_i686_gnu" 554 | version = "0.52.4" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 557 | 558 | [[package]] 559 | name = "windows_i686_msvc" 560 | version = "0.52.4" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 563 | 564 | [[package]] 565 | name = "windows_x86_64_gnu" 566 | version = "0.52.4" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 569 | 570 | [[package]] 571 | name = "windows_x86_64_gnullvm" 572 | version = "0.52.4" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 575 | 576 | [[package]] 577 | name = "windows_x86_64_msvc" 578 | version = "0.52.4" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 581 | 582 | [[package]] 583 | name = "winnow" 584 | version = "0.6.5" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" 587 | dependencies = [ 588 | "memchr", 589 | ] 590 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vitasdk-sys" 3 | version = "0.3.3" 4 | authors = [ 5 | "Aphek ", 6 | "Daria Sukhonina ", 7 | ] 8 | edition = "2021" 9 | license = "MIT OR Apache-2.0" 10 | repository = "https://github.com/vita-rust/vitasdk-sys" 11 | homepage = "https://github.com/vita-rust/vitasdk-sys" 12 | description = "Raw bindings to vitasdk" 13 | keywords = ["vitasdk", "psvita", "vita", "ffi"] 14 | categories = ["external-ffi-bindings"] 15 | exclude = ["vita-headers"] 16 | 17 | [workspace] 18 | members = ["build-util"] 19 | 20 | [profile.release] 21 | lto = true 22 | 23 | [profile.build-util] 24 | inherits = "dev" 25 | debug = false 26 | 27 | [build-dependencies] 28 | env_logger = { version = "0.11.2", optional = true } 29 | 30 | [build-dependencies.vitasdk-sys-build-util] 31 | path = "build-util" 32 | version = "0.2.0" 33 | optional = true 34 | 35 | [package.metadata.docs.rs] 36 | features = ["all-stubs", "log-build", "vitasdk-utils"] 37 | rustdoc-args = ["--cfg", "docsrs"] 38 | default-target = "armv7-sony-vita-newlibeabihf" 39 | targets = [] 40 | cargo-args = ["-Z", "build-std"] 41 | 42 | [features] 43 | bindgen = ["vitasdk-sys-build-util"] 44 | log-build = ["dep:env_logger"] 45 | 46 | vitasdk-utils = [] 47 | 48 | # Automatically generated by build-util: 49 | all-stubs = [ 50 | "SceAVConfig_stub", 51 | "SceAppMgrForDriver_stub", 52 | "SceAppMgr_stub", 53 | "SceAppUtil_stub", 54 | "SceAtrac_stub", 55 | "SceAudioIn_stub", 56 | "SceAudio_stub", 57 | "SceAudiodec_stub", 58 | "SceAudioenc_stub", 59 | "SceAvPlayer_stub", 60 | "SceAvcodecForDriver_stub", 61 | "SceAvcodecUser_stub", 62 | "SceAvcodec_stub", 63 | "SceBacktraceForDriver_stub", 64 | "SceBbmc_stub", 65 | "SceBgAppUtil_stub", 66 | "SceBtForDriver_stub", 67 | "SceBt_stub", 68 | "SceCameraForDriver_stub", 69 | "SceCamera_stub", 70 | "SceClipboard_stub", 71 | "SceClockgenForDriver_stub", 72 | "SceCodecEnginePerf_stub", 73 | "SceCodecEngineWrapper_stub", 74 | "SceCodecEngine_stub", 75 | "SceCommonDialog_stub", 76 | "SceCompat_stub", 77 | "SceCoredumpForDriver_stub", 78 | "SceCoredump_stub", 79 | "SceCpuForDriver_stub", 80 | "SceCpuForKernel_363_stub", 81 | "SceCpuForKernel_stub", 82 | "SceCtrlForDriver_stub", 83 | "SceCtrl_stub", 84 | "SceDTrace_stub", 85 | "SceDebugForDriver_stub", 86 | "SceDebugForKernel_363_stub", 87 | "SceDebugForKernel_stub", 88 | "SceDebugLedForDriver_stub", 89 | "SceDeci4pDbgpForDriver_stub", 90 | "SceDeci4pUserp_stub", 91 | "SceDipswForDriver_stub", 92 | "SceDisplayForDriver_stub", 93 | "SceDisplay_stub", 94 | "SceDmacmgrForDriver_stub", 95 | "SceDriverUser_stub", 96 | "SceDsiForDriver_stub", 97 | "SceError_stub", 98 | "SceExcpmgrForKernel_363_stub", 99 | "SceExcpmgrForKernel_stub", 100 | "SceFace_stub", 101 | "SceFiber_stub", 102 | "SceFios2KernelForDriver_stub", 103 | "SceFios2Kernel_stub", 104 | "SceFios2_stub", 105 | "SceGameUpdate_stub", 106 | "SceGpioForDriver_stub", 107 | "SceGps_stub", 108 | "SceGpuEs4ForDriver_stub", 109 | "SceGpuEs4_stub", 110 | "SceGxm_stub", 111 | "SceHandwriting_stub", 112 | "SceHidForDriver_stub", 113 | "SceHid_stub", 114 | "SceHttp_stub", 115 | "SceI2cForDriver_stub", 116 | "SceIdStorageForDriver_stub", 117 | "SceIftuForDriver_stub", 118 | "SceIme_stub", 119 | "SceIncomingDialog_stub", 120 | "SceIntrmgrForDriver_stub", 121 | "SceIntrmgrForKernel_stub", 122 | "SceIofilemgrForDriver_stub", 123 | "SceIofilemgr_stub", 124 | "SceJpegArm_stub", 125 | "SceJpegEncArm_stub", 126 | "SceJpegEnc_stub", 127 | "SceJpeg_stub", 128 | "SceKernelBootimage_stub", 129 | "SceKernelDmacMgr_stub", 130 | "SceKernelModulemgr_stub", 131 | "SceKernelSuspendForDriver_stub", 132 | "SceKernelThreadMgr_stub", 133 | "SceKernelUtilsForDriver_stub", 134 | "SceLcdForDriver_stub", 135 | "SceLedForDriver_stub", 136 | "SceLibDbg_stub", 137 | "SceLibG729_stub", 138 | "SceLibJson_stub", 139 | "SceLibKernel_stub", 140 | "SceLibMono_stub", 141 | "SceLibMp4Recorder_stub", 142 | "SceLibMtp_stub", 143 | "SceLibXml_stub", 144 | "SceLiveArea_stub", 145 | "SceLocationExtension_stub", 146 | "SceLocation_stub", 147 | "SceLsdb_stub", 148 | "SceModulemgrForDriver_stub", 149 | "SceModulemgrForKernel_363_stub", 150 | "SceModulemgrForKernel_stub", 151 | "SceMotionDevForDriver_stub", 152 | "SceMotionDev_stub", 153 | "SceMotion_stub", 154 | "SceMsifForDriver_stub", 155 | "SceMtpIfDriver_stub", 156 | "SceMusicExport_stub", 157 | "SceNearDialogUtil_stub", 158 | "SceNearUtil_stub", 159 | "SceNetAdhocMatching_stub", 160 | "SceNetCtl_stub", 161 | "SceNetPsForDriver_stub", 162 | "SceNetPs_stub", 163 | "SceNet_stub", 164 | "SceNgsUser_stub", 165 | "SceNgs_stub", 166 | "SceNotificationUtil_stub", 167 | "SceNpActivity_stub", 168 | "SceNpBasic_stub", 169 | "SceNpCommerce2_stub", 170 | "SceNpCommon_stub", 171 | "SceNpDrmForDriver_stub", 172 | "SceNpDrm_stub", 173 | "SceNpManager_stub", 174 | "SceNpMatching2_stub", 175 | "SceNpMessage_stub", 176 | "SceNpParty_stub", 177 | "SceNpScore_stub", 178 | "SceNpSignaling_stub", 179 | "SceNpSnsFacebook_stub", 180 | "SceNpTrophy_stub", 181 | "SceNpTus_stub", 182 | "SceNpUtility_stub", 183 | "SceNpWebApi_stub", 184 | "SceOledForDriver_stub", 185 | "ScePaf_stub", 186 | "ScePamgr_stub", 187 | "ScePerf_stub", 188 | "ScePervasiveForDriver_stub", 189 | "ScePfsMgrForKernel_stub", 190 | "ScePgf_stub", 191 | "ScePhotoExport_stub", 192 | "ScePmMgrForDriver_stub", 193 | "ScePowerForDriver_stub", 194 | "ScePower_stub", 195 | "SceProcEventForDriver_stub", 196 | "SceProcessmgrForDriver_stub", 197 | "SceProcessmgrForKernel_363_stub", 198 | "SceProcessmgrForKernel_stub", 199 | "SceProcessmgr_stub", 200 | "ScePromoterUtil_stub", 201 | "ScePsmDrmForDriver_stub", 202 | "ScePspnetAdhoc_stub", 203 | "ScePvf_stub", 204 | "SceQafMgrForDriver_stub", 205 | "SceRazorCapture_stub", 206 | "SceRazorHud_stub", 207 | "SceRegMgrForDriver_stub", 208 | "SceRegMgrServiceForDriver_stub", 209 | "SceRegistryMgr_stub", 210 | "SceRtcForDriver_stub", 211 | "SceRtc_stub", 212 | "SceRudp_stub", 213 | "SceSas_stub", 214 | "SceSblACMgrForDriver_stub", 215 | "SceSblACMgrForKernel_stub", 216 | "SceSblACMgr_stub", 217 | "SceSblAIMgrForDriver_stub", 218 | "SceSblAuthMgrForDriver_stub", 219 | "SceSblAuthMgrForKernel_stub", 220 | "SceSblFwLoaderForDriver_stub", 221 | "SceSblGcAuthMgr_stub", 222 | "SceSblPostSsMgrForDriver_stub", 223 | "SceSblPostSsMgr_stub", 224 | "SceSblSmCommForKernel_stub", 225 | "SceSblSmSchedProxyForKernel_stub", 226 | "SceSblSsMgrForDriver_stub", 227 | "SceSblSsMgrForKernel_stub", 228 | "SceSblSsMgr_stub", 229 | "SceSblUpdateMgr_stub", 230 | "SceScreenShot_stub", 231 | "SceSdifForDriver_stub", 232 | "SceShaccCg_stub", 233 | "SceShellSvc_stub", 234 | "SceShutterSound_stub", 235 | "SceSmart_stub", 236 | "SceSqlite_stub", 237 | "SceSsl_stub", 238 | "SceStdio_0931_stub", 239 | "SceSulpha_stub", 240 | "SceSysconForDriver_stub", 241 | "SceSysmemForDriver_0990_stub", 242 | "SceSysmemForDriver_stub", 243 | "SceSysmemForKernel_363_stub", 244 | "SceSysmemForKernel_stub", 245 | "SceSysmem_stub", 246 | "SceSysmodule_stub", 247 | "SceSysrootForDriver_stub", 248 | "SceSysrootForKernel_stub", 249 | "SceSystemGesture_stub", 250 | "SceSystimerForDriver_stub", 251 | "SceTeleportClient_stub", 252 | "SceTeleportServer_stub", 253 | "SceThreadmgrForDriver_stub", 254 | "SceThreadmgrForKernel_363_stub", 255 | "SceThreadmgrForKernel_stub", 256 | "SceTouchForDriver_stub", 257 | "SceTouch_stub", 258 | "SceTriggerUtil_stub", 259 | "SceUartForKernel_363_stub", 260 | "SceUartForKernel_stub", 261 | "SceUdcdForDriver_stub", 262 | "SceUdcd_stub", 263 | "SceUlobjMgr_stub", 264 | "SceUlt_stub", 265 | "SceUsbAudioForDriver_stub", 266 | "SceUsbAudioIn_stub", 267 | "SceUsbPspcm_stub", 268 | "SceUsbSerialForDriver_stub", 269 | "SceUsbSerial_stub", 270 | "SceUsbServForDriver_stub", 271 | "SceUsbServ_stub", 272 | "SceUsbdForDriver_stub", 273 | "SceUsbd_stub", 274 | "SceUsbstorVStorDriver_stub", 275 | "SceVideoExport_stub", 276 | "SceVideodec_stub", 277 | "SceVoiceQoS_stub", 278 | "SceVoice_stub", 279 | "SceVshBridge_stub", 280 | "SceWlanBtForDriver_stub", 281 | "SceWlanBt_stub", 282 | "libScePiglet_stub", 283 | ] 284 | SceAVConfig_stub = [] 285 | SceAppMgrForDriver_stub = [] 286 | SceAppMgr_stub = [] 287 | SceAppUtil_stub = [] 288 | SceAtrac_stub = [] 289 | SceAudioIn_stub = [] 290 | SceAudio_stub = [] 291 | SceAudiodec_stub = [] 292 | SceAudioenc_stub = [] 293 | SceAvPlayer_stub = [] 294 | SceAvcodecForDriver_stub = [] 295 | SceAvcodecUser_stub = [] 296 | SceAvcodec_stub = [] 297 | SceBacktraceForDriver_stub = [] 298 | SceBbmc_stub = [] 299 | SceBgAppUtil_stub = [] 300 | SceBtForDriver_stub = [] 301 | SceBt_stub = [] 302 | SceCameraForDriver_stub = [] 303 | SceCamera_stub = [] 304 | SceClipboard_stub = [] 305 | SceClockgenForDriver_stub = [] 306 | SceCodecEnginePerf_stub = [] 307 | SceCodecEngineWrapper_stub = [] 308 | SceCodecEngine_stub = [] 309 | SceCommonDialog_stub = [] 310 | SceCompat_stub = [] 311 | SceCoredumpForDriver_stub = [] 312 | SceCoredump_stub = [] 313 | SceCpuForDriver_stub = [] 314 | SceCpuForKernel_363_stub = [] 315 | SceCpuForKernel_stub = [] 316 | SceCtrlForDriver_stub = [] 317 | SceCtrl_stub = [] 318 | SceDTrace_stub = [] 319 | SceDebugForDriver_stub = [] 320 | SceDebugForKernel_363_stub = [] 321 | SceDebugForKernel_stub = [] 322 | SceDebugLedForDriver_stub = [] 323 | SceDeci4pDbgpForDriver_stub = [] 324 | SceDeci4pUserp_stub = [] 325 | SceDipswForDriver_stub = [] 326 | SceDisplayForDriver_stub = [] 327 | SceDisplay_stub = [] 328 | SceDmacmgrForDriver_stub = [] 329 | SceDriverUser_stub = [] 330 | SceDsiForDriver_stub = [] 331 | SceError_stub = [] 332 | SceExcpmgrForKernel_363_stub = [] 333 | SceExcpmgrForKernel_stub = [] 334 | SceFace_stub = [] 335 | SceFiber_stub = [] 336 | SceFios2KernelForDriver_stub = [] 337 | SceFios2Kernel_stub = [] 338 | SceFios2_stub = [] 339 | SceGameUpdate_stub = [] 340 | SceGpioForDriver_stub = [] 341 | SceGps_stub = [] 342 | SceGpuEs4ForDriver_stub = [] 343 | SceGpuEs4_stub = [] 344 | SceGxm_stub = [] 345 | SceHandwriting_stub = [] 346 | SceHidForDriver_stub = [] 347 | SceHid_stub = [] 348 | SceHttp_stub = [] 349 | SceI2cForDriver_stub = [] 350 | SceIdStorageForDriver_stub = [] 351 | SceIftuForDriver_stub = [] 352 | SceIme_stub = [] 353 | SceIncomingDialog_stub = [] 354 | SceIntrmgrForDriver_stub = [] 355 | SceIntrmgrForKernel_stub = [] 356 | SceIofilemgrForDriver_stub = [] 357 | SceIofilemgr_stub = [] 358 | SceJpegArm_stub = [] 359 | SceJpegEncArm_stub = [] 360 | SceJpegEnc_stub = [] 361 | SceJpeg_stub = [] 362 | SceKernelBootimage_stub = [] 363 | SceKernelDmacMgr_stub = [] 364 | SceKernelModulemgr_stub = [] 365 | SceKernelSuspendForDriver_stub = [] 366 | SceKernelThreadMgr_stub = [] 367 | SceKernelUtilsForDriver_stub = [] 368 | SceLcdForDriver_stub = [] 369 | SceLedForDriver_stub = [] 370 | SceLibDbg_stub = [] 371 | SceLibG729_stub = [] 372 | SceLibJson_stub = [] 373 | SceLibKernel_stub = [] 374 | SceLibMonoBridge_stub = [] 375 | SceLibMono_stub = [] 376 | SceLibMp4Recorder_stub = [] 377 | SceLibMtp_stub = [] 378 | SceLibXml_stub = [] 379 | SceLibc_stub = [] 380 | SceLiveArea_stub = [] 381 | SceLocationExtension_stub = [] 382 | SceLocation_stub = [] 383 | SceLsdb_stub = [] 384 | SceModulemgrForDriver_stub = [] 385 | SceModulemgrForKernel_363_stub = [] 386 | SceModulemgrForKernel_stub = [] 387 | SceMotionDevForDriver_stub = [] 388 | SceMotionDev_stub = [] 389 | SceMotion_stub = [] 390 | SceMsifForDriver_stub = [] 391 | SceMtpIfDriver_stub = [] 392 | SceMusicExport_stub = [] 393 | SceNearDialogUtil_stub = [] 394 | SceNearUtil_stub = [] 395 | SceNetAdhocMatching_stub = [] 396 | SceNetCtl_stub = [] 397 | SceNetPsForDriver_stub = [] 398 | SceNetPs_stub = [] 399 | SceNet_stub = [] 400 | SceNgsUser_stub = [] 401 | SceNgs_stub = [] 402 | SceNotificationUtil_stub = [] 403 | SceNpActivity_stub = [] 404 | SceNpBasic_stub = [] 405 | SceNpCommerce2_stub = [] 406 | SceNpCommon_stub = [] 407 | SceNpDrmForDriver_stub = [] 408 | SceNpDrm_stub = [] 409 | SceNpManager_stub = [] 410 | SceNpMatching2_stub = [] 411 | SceNpMessage_stub = [] 412 | SceNpParty_stub = [] 413 | SceNpScore_stub = [] 414 | SceNpSignaling_stub = [] 415 | SceNpSnsFacebook_stub = [] 416 | SceNpTrophy_stub = [] 417 | SceNpTus_stub = [] 418 | SceNpUtility_stub = [] 419 | SceNpWebApi_stub = [] 420 | SceOledForDriver_stub = [] 421 | ScePaf_stub = [] 422 | ScePamgr_stub = [] 423 | ScePerf_stub = [] 424 | ScePervasiveForDriver_stub = [] 425 | ScePfsMgrForKernel_stub = [] 426 | ScePgf_stub = [] 427 | ScePhotoExport_stub = [] 428 | ScePmMgrForDriver_stub = [] 429 | ScePowerForDriver_stub = [] 430 | ScePower_stub = [] 431 | SceProcEventForDriver_stub = [] 432 | SceProcessmgrForDriver_stub = [] 433 | SceProcessmgrForKernel_363_stub = [] 434 | SceProcessmgrForKernel_stub = [] 435 | SceProcessmgr_stub = [] 436 | ScePromoterUtil_stub = [] 437 | ScePsmDrmForDriver_stub = [] 438 | ScePspnetAdhoc_stub = [] 439 | ScePvf_stub = [] 440 | SceQafMgrForDriver_stub = [] 441 | SceRazorCapture_stub = [] 442 | SceRazorHud_stub = [] 443 | SceRegMgrForDriver_stub = [] 444 | SceRegMgrServiceForDriver_stub = [] 445 | SceRegistryMgr_stub = [] 446 | SceRtabi_stub = [] 447 | SceRtcForDriver_stub = [] 448 | SceRtc_stub = [] 449 | SceRudp_stub = [] 450 | SceSas_stub = [] 451 | SceSblACMgrForDriver_stub = [] 452 | SceSblACMgrForKernel_stub = [] 453 | SceSblACMgr_stub = [] 454 | SceSblAIMgrForDriver_stub = [] 455 | SceSblAuthMgrForDriver_stub = [] 456 | SceSblAuthMgrForKernel_stub = [] 457 | SceSblFwLoaderForDriver_stub = [] 458 | SceSblGcAuthMgr_stub = [] 459 | SceSblPostSsMgrForDriver_stub = [] 460 | SceSblPostSsMgr_stub = [] 461 | SceSblSmCommForKernel_stub = [] 462 | SceSblSmSchedProxyForKernel_stub = [] 463 | SceSblSsMgrForDriver_stub = [] 464 | SceSblSsMgrForKernel_stub = [] 465 | SceSblSsMgr_stub = [] 466 | SceSblUpdateMgr_stub = [] 467 | SceScreenShot_stub = [] 468 | SceSdifForDriver_stub = [] 469 | SceShaccCg_stub = [] 470 | SceShellSvc_stub = [] 471 | SceShutterSound_stub = [] 472 | SceSmart_stub = [] 473 | SceSqlite_stub = [] 474 | SceSsl_stub = [] 475 | SceStdio_0931_stub = [] 476 | SceSulpha_stub = [] 477 | SceSysclibForDriver_stub = [] 478 | SceSysconForDriver_stub = [] 479 | SceSysmemForDriver_0990_stub = [] 480 | SceSysmemForDriver_stub = [] 481 | SceSysmemForKernel_363_stub = [] 482 | SceSysmemForKernel_stub = [] 483 | SceSysmem_stub = [] 484 | SceSysmodule_stub = [] 485 | SceSysrootForDriver_stub = [] 486 | SceSysrootForKernel_stub = [] 487 | SceSystemGesture_stub = [] 488 | SceSystimerForDriver_stub = [] 489 | SceTeleportClient_stub = [] 490 | SceTeleportServer_stub = [] 491 | SceThreadmgrForDriver_stub = [] 492 | SceThreadmgrForKernel_363_stub = [] 493 | SceThreadmgrForKernel_stub = [] 494 | SceTouchForDriver_stub = [] 495 | SceTouch_stub = [] 496 | SceTriggerUtil_stub = [] 497 | SceUartForKernel_363_stub = [] 498 | SceUartForKernel_stub = [] 499 | SceUdcdForDriver_stub = [] 500 | SceUdcd_stub = [] 501 | SceUlobjMgr_stub = [] 502 | SceUlt_stub = [] 503 | SceUsbAudioForDriver_stub = [] 504 | SceUsbAudioIn_stub = [] 505 | SceUsbPspcm_stub = [] 506 | SceUsbSerialForDriver_stub = [] 507 | SceUsbSerial_stub = [] 508 | SceUsbServForDriver_stub = [] 509 | SceUsbServ_stub = [] 510 | SceUsbdForDriver_stub = [] 511 | SceUsbd_stub = [] 512 | SceUsbstorVStorDriver_stub = [] 513 | SceVideoExport_stub = [] 514 | SceVideodec_stub = [] 515 | SceVoiceQoS_stub = [] 516 | SceVoice_stub = [] 517 | SceVshBridge_stub = [] 518 | SceWlanBtForDriver_stub = [] 519 | SceWlanBt_stub = [] 520 | libScePiglet_stub = [] 521 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Aphek Brito, Daria Sukhonina 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Aphek Brito, Daria Sukhonina 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | If you're interested in PS Vita development in Rust, please check out the [organization-wide docs](https://github.com/vita-rust) and the [Rust on Sony PlayStation Vita Book](https://vita-rust.github.io/book/). 2 | There are also working examples at the [examples](https://github.com/vita-rust/examples) repo. 3 | 4 | # vitasdk-sys 5 | 6 | [![docs.rs](https://docs.rs/vitasdk-sys/badge.svg)](https://docs.rs/vitasdk-sys/) 7 | [![Crates.io](https://img.shields.io/crates/v/vitasdk-sys.svg)](https://crates.io/crates/vitasdk-sys) 8 | ![License: MIT](https://img.shields.io/crates/l/vitasdk-sys.svg) 9 | 10 | 11 | This crate exports bindings to functions available in [vitasdk](https://vitasdk.org/) and statically links to its stubs libraries based on enabled features. Their official docs are [here](https://docs.vitasdk.org/) and the bindings are automatically generated from vitasdk's [vita-headers](https://github.com/vitasdk/vita-headers) repository. Which features required for which functions can be found on https://docs.rs/vitasdk-sys. 12 | 13 | There's an example on how to use this crate at [vita-rust/examples/crates/4-vitasdk](https://github.com/vita-rust/examples/tree/main/crates/4-vitasdk). 14 | 15 | To be able to use it, you need vitasdk available and the environment variable `VITASDK` set to its location. e.g.: 16 | 17 | ``` 18 | $ export VITASDK=/opt/vitasdk 19 | ``` 20 | 21 | ## Features 22 | 23 | ### Stubs (`*_stub`) 24 | 25 | To be able to use any function available in this crate, you'll need to enable 26 | the related features, which will cause the required stub to be linked. You can 27 | find which any function a stub requires by looking at [docs.rs/vitasdk-sys](https://docs.rs/vitasdk-sys). 28 | 29 | Example: to find which stub is required to use `sceDisplaySetFrameBuf`, search 30 | for it on docs.rs. You'll find `Available on crate feature SceDisplay_stub only.` 31 | there, which means that you'll need to enable `SceDisplay_stub` to use it. 32 | 33 | > ℹ️ **NOTE**: There are a few (currently 4) conflicting stubs, which are stubs 34 | that define symbols that are also defined by compiler builtins or std. A list of 35 | those features can be found [here](https://github.com/vita-rust/vitasdk-sys/blob/main/build-util/src/vita_headers_db.rs#L10). 36 | 37 | ### `vitasdk-utils` 38 | 39 | This feature just enables some functions provided by vitasdk. Just like the 40 | stubs, you can figure which functions require it by looking at docs.rs. 41 | 42 | ### `bindgen` 43 | 44 | The `bindgen` feature makes the crate generate bindings at compile-time 45 | using headers from the system's vitasdk (on `$VITASDK`), instead of using the 46 | pre-generated bindings. 47 | 48 | To use this feature you also need [bindgen's requirements](https://rust-lang.github.io/rust-bindgen/requirements.html), 49 | which may already be on your system. 50 | 51 | ## Manually updating the submodule 52 | 53 | ## Updating 54 | 55 | To update the headers, we have a job that runs on GitHub Actions yearly or on demand that will create a PR. If you want to update manually, you can follow these steps: 56 | 57 | ### Manually 58 | 59 | Clone the repository with submodules (the C headers): 60 | 61 | ```sh 62 | $ git clone --recurse-submodules https://github.com/pheki/vitasdk-sys.git 63 | ``` 64 | 65 | If the repository is already cloned, update the submodules with: 66 | 67 | ```sh 68 | $ git submodule update --init --recursive 69 | ``` 70 | 71 | To update the headers, go to the vita-headers submodule and update it by the usual means: 72 | 73 | ``` 74 | $ cd vita-headers 75 | $ git pull 76 | $ cd .. 77 | ``` 78 | 79 | Then run `cargo run -p vitasdk-sys-build-util -- bindgen` 80 | 81 | > ℹ️ **NOTE**: The LLVM version currently used in CI is 16. Occasionally there may be slight differences in generated bindings depending on your LLVM version. 82 | 83 | ## Versioning 84 | 85 | Usual `semver` rules apply for this crate, but note that there may be differences between the version of the headers used to generate the bindings and the vitasdk version installed on your machine. 86 | 87 | ## Updating 88 | 89 | To update versions you can look for breaking changes at [CHANGELOG.md](CHANGELOG.md). 90 | If you're coming from a version before 0.3, [this comment](https://github.com/vita-rust/vitasdk-sys/issues/20#issuecomment-1782335568) has a migration guide. 91 | 92 | ## Credits 93 | 94 | - [**VitaSDK team**](http://vitasdk.org/) for the toolchain, vitasdk itself, etc. 95 | - [rust-bindgen contributors](https://github.com/rust-lang/rust-bindgen) for making auto generated bindings viable. 96 | - [Martin Larralde](https://github.com/althonos) for [psp2-sys](https://github.com/vita-rust/psp2-sys), which I believe originally inspired me to create this crate. 97 | 98 | ## License 99 | 100 | This crate (library) is distributed under terms of MIT license or Apache License (Version 2.0), at your option. 101 | See `LICENSE-MIT` and `LICENSE-APACHE` for terms. 102 | -------------------------------------------------------------------------------- /build-util/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vitasdk-sys-build-util" 3 | version = "0.2.0" 4 | edition = "2021" 5 | authors = ["Daria Sukhonina "] 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/vita-rust/vitasdk-sys" 8 | homepage = "https://github.com/vita-rust/vitasdk-sys" 9 | description = "Internal build utilities for raw bindings to vitasdk" 10 | keywords = ["vitasdk", "psvita", "vita"] 11 | 12 | [dependencies] 13 | env_logger = "0.11.2" 14 | log = "0.4.20" 15 | serde = { version = "1.0.194", features = ["derive"] } 16 | serde_yaml = "0.9.30" 17 | syn = { version = "2.0.46", default-features = false, features = ["parsing", "full", "printing", "visit-mut", "extra-traits"] } 18 | proc-macro2 = { version = "1.0.76", default-features = false } 19 | toml = { version = "0.8.8", default-features = false, features = ["parse"] } 20 | bindgen = "0.69.4" 21 | quote = { version = "1.0.35", default-features = false } 22 | -------------------------------------------------------------------------------- /build-util/src/bindgen.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs, io, path::Path, process}; 2 | 3 | use quote::ToTokens; 4 | use syn::visit_mut::VisitMut; 5 | 6 | use crate::{ 7 | visitors::{Link, Sort}, 8 | vita_headers_db::VitaDb, 9 | }; 10 | 11 | pub fn generate( 12 | vita_headers_include: &Path, 13 | db: &Path, 14 | bindings_output: &Path, 15 | vitasdk_sys_manifest: &Path, 16 | is_build_rs: bool, 17 | ) { 18 | log::info!("Generating preprocessed bindings"); 19 | let headers = vitasdk_sys_manifest.parent().unwrap().join("headers"); 20 | let bindings = generate_preprocessed_bindings(&headers, vita_headers_include, is_build_rs); 21 | 22 | let mut bindings = syn::parse_file(&bindings).expect("failed to parse file"); 23 | 24 | log::info!( 25 | "Loading vita-headers metadata yaml files from \"{}\"", 26 | db.to_string_lossy() 27 | ); 28 | let db = VitaDb::load(db); 29 | let link = Link::load(&db); 30 | 31 | if is_build_rs { 32 | db.check_missing_manifest_features(vitasdk_sys_manifest); 33 | } else { 34 | db.update_manifest_features(vitasdk_sys_manifest); 35 | } 36 | 37 | link.visit(&mut bindings); 38 | 39 | // We sort items here so generated bindings don't depend on the included order. 40 | Sort.visit_file_mut(&mut bindings); 41 | 42 | let bindings = bindings.into_token_stream(); 43 | 44 | { 45 | log::info!( 46 | "Writing postprocessed bindings into {}", 47 | bindings_output.to_string_lossy() 48 | ); 49 | let mut bindings_output = io::BufWriter::new(fs::File::create(bindings_output).unwrap()); 50 | use std::io::Write; 51 | write!(bindings_output, "{bindings}").unwrap(); 52 | } 53 | 54 | let cargo = env::var_os("CARGO"); 55 | let mut fmt_cmd = process::Command::new(cargo.as_deref().unwrap_or_else(|| "cargo".as_ref())); 56 | fmt_cmd.args(["fmt", "--"]); 57 | fmt_cmd.arg(bindings_output); 58 | 59 | log::info!("Running formatting command: {fmt_cmd:?}"); 60 | 61 | let fmt_result = fmt_cmd.status(); 62 | match fmt_result { 63 | Ok(status) => { 64 | if status.success() { 65 | log::info!("Formatting command finished"); 66 | } else if is_build_rs { 67 | log::warn!("Formatting command failed with status: {status:?}"); 68 | } else { 69 | panic!("Formatting command failed with status: {status:?}"); 70 | } 71 | } 72 | Err(error) => { 73 | if is_build_rs { 74 | log::warn!("Formatting command failed with error: {error:?}"); 75 | } else { 76 | panic!("Formatting command failed with error: {error:?}"); 77 | } 78 | } 79 | } 80 | } 81 | 82 | fn generate_preprocessed_bindings( 83 | headers: &Path, 84 | vita_headers_include: &Path, 85 | is_build_rs: bool, 86 | ) -> String { 87 | let builder = bindgen::Builder::default() 88 | .header(vita_headers_include.join("vitasdk.h").to_str().unwrap()) 89 | .header(vita_headers_include.join("vitasdkkern.h").to_str().unwrap()) 90 | .clang_arg("-I".to_string() + headers.to_str().unwrap()) 91 | .clang_arg("-I".to_string() + vita_headers_include.to_str().unwrap()) 92 | .clang_args(&["-target", "armv7a-none-eabihf"]) 93 | .use_core() 94 | .ctypes_prefix("crate::ctypes") 95 | .generate_comments(false) 96 | .prepend_enum_name(false) 97 | .layout_tests(false) 98 | .formatter(bindgen::Formatter::None); 99 | 100 | let builder = if is_build_rs { 101 | builder.parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) 102 | } else { 103 | builder 104 | }; 105 | 106 | builder.generate().expect("bindgen failed").to_string() 107 | } 108 | -------------------------------------------------------------------------------- /build-util/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bindgen; 2 | pub mod vita_headers_db; 3 | 4 | mod visitors; 5 | -------------------------------------------------------------------------------- /build-util/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{BTreeSet, HashSet}, 3 | env, 4 | path::PathBuf, 5 | process::{self, Command, ExitCode}, 6 | }; 7 | 8 | use vitasdk_sys_build_util::vita_headers_db::{ 9 | missing_features_filter, missing_libs_filter, VitaDb, 10 | }; 11 | 12 | fn vitasdk_sys_manifest() -> PathBuf { 13 | let cargo = env::var_os("CARGO"); 14 | let output = Command::new(cargo.as_deref().unwrap_or("cargo".as_ref())) 15 | .args(["locate-project", "--message-format", "plain", "--workspace"]) 16 | .stderr(process::Stdio::inherit()) 17 | .output() 18 | .unwrap(); 19 | assert!( 20 | output.status.success(), 21 | "Could not cargo locate-project; perhaps running outside from workspace directory?" 22 | ); 23 | String::from_utf8(output.stdout).unwrap().trim().into() 24 | } 25 | 26 | fn vita_headers_db_path() -> PathBuf { 27 | vitasdk_sys_manifest() 28 | .parent() 29 | .unwrap() 30 | .join("vita-headers/db") 31 | } 32 | 33 | fn print_help() { 34 | eprintln!( 35 | "\ 36 | Internal build utilities for vitasdk-sys crate 37 | 38 | USAGE: 39 | vitasdk-sys-build-util [OPTIONS] 40 | 41 | Commands: 42 | stub-libs Print all stub lib names 43 | bindgen Generate vitasdk-sys bindings 44 | help Print help 45 | 46 | Options 47 | -h, --help Print help 48 | " 49 | ) 50 | } 51 | 52 | fn main() -> ExitCode { 53 | env_logger::init(); 54 | 55 | let cmd = std::env::args().nth(1); 56 | match cmd.as_deref() { 57 | Some("stub-libs") => stub_libs(), 58 | Some("bindgen") => bindgen(), 59 | Some("help" | "--help" | "-h") => { 60 | print_help(); 61 | ExitCode::SUCCESS 62 | } 63 | _ => { 64 | print_help(); 65 | ExitCode::FAILURE 66 | } 67 | } 68 | } 69 | 70 | fn stub_libs() -> ExitCode { 71 | fn print_help() { 72 | eprintln!( 73 | "\ 74 | Print stub lib names 75 | 76 | USAGE: 77 | vitasdk-sys-build-util stub-libs [OPTIONS] 78 | 79 | Options: 80 | -h, --help Print help 81 | -u, --user Print only user stub libs. Mutually exclusive with `--kernel`. 82 | -k, --kernel Print only kernel stub libs. Mutually exclusive with `--user`. 83 | -c, --conflicting Print only stub libs with conflicting symbols 84 | --with-conflicting Include stub libs with conflicting symbols 85 | --missing-features Print only undefined vitasdk-sys stub features 86 | --missing-libs Print only stub libs which do not exist in `$VITASDK/arm-vita-eabi/lib` 87 | --fail-if-any Fail if any stub lib is printed 88 | " 89 | ) 90 | } 91 | 92 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] 93 | enum Flag { 94 | Help, 95 | User, 96 | Kernel, 97 | Conflicting, 98 | WithConflicting, 99 | MissingFeatures, 100 | MissingLibs, 101 | FailIfAny, 102 | } 103 | 104 | #[derive(Debug)] 105 | struct ParseFlagError; 106 | 107 | impl std::str::FromStr for Flag { 108 | type Err = ParseFlagError; 109 | 110 | fn from_str(s: &str) -> Result { 111 | match s { 112 | "-h" | "--help" => Ok(Flag::Help), 113 | "-u" | "--user" => Ok(Flag::User), 114 | "-k" | "--kernel" => Ok(Flag::Kernel), 115 | "-c" | "--conflicting" => Ok(Flag::Conflicting), 116 | "--with-conflicting" => Ok(Flag::WithConflicting), 117 | "--missing-features" => Ok(Flag::MissingFeatures), 118 | "--missing-libs" => Ok(Flag::MissingLibs), 119 | "--fail-if-any" => Ok(Flag::FailIfAny), 120 | _ => Err(ParseFlagError), 121 | } 122 | } 123 | } 124 | 125 | let Some(options) = std::env::args() 126 | .skip(2) 127 | .filter(|a| !a.is_empty()) 128 | .map(|op| op.parse()) 129 | .collect::, ParseFlagError>>() 130 | .ok() 131 | .filter(|ops| !ops.contains(&Flag::Kernel) || !ops.contains(&Flag::User)) 132 | else { 133 | print_help(); 134 | return ExitCode::FAILURE; 135 | }; 136 | 137 | if options.contains(&Flag::Help) { 138 | print_help(); 139 | return ExitCode::SUCCESS; 140 | } 141 | 142 | let mut db = VitaDb::load(&vita_headers_db_path()); 143 | if options.contains(&Flag::Conflicting) { 144 | db = db.split_conflicting(); 145 | } else if !options.contains(&Flag::WithConflicting) { 146 | db.split_conflicting(); 147 | } 148 | 149 | if options.contains(&Flag::User) { 150 | db.split_kernel(); 151 | } else if options.contains(&Flag::Kernel) { 152 | db = db.split_kernel(); 153 | } 154 | 155 | let vitasdk_sys_manifest = vitasdk_sys_manifest(); 156 | let stub_libs: BTreeSet<_> = { 157 | let mut missing_features_filter = options 158 | .contains(&Flag::MissingFeatures) 159 | .then(|| missing_features_filter(&vitasdk_sys_manifest)); 160 | let mut missing_libs_filter = options 161 | .contains(&Flag::MissingLibs) 162 | .then(missing_libs_filter); 163 | 164 | db.stub_lib_names() 165 | .filter(|s| { 166 | missing_features_filter 167 | .as_mut() 168 | .map(|f| f(s)) 169 | .unwrap_or(true) 170 | }) 171 | .filter(|s| missing_libs_filter.as_mut().map(|f| f(s)).unwrap_or(true)) 172 | .collect() 173 | }; 174 | 175 | { 176 | use std::io::{self, Write}; 177 | 178 | let mut stdout = io::stdout().lock(); 179 | stub_libs 180 | .iter() 181 | .for_each(|stub_lib| writeln!(stdout, "{stub_lib}").unwrap()); 182 | } 183 | 184 | if !stub_libs.is_empty() && options.contains(&Flag::FailIfAny) { 185 | return ExitCode::FAILURE; 186 | } 187 | 188 | ExitCode::SUCCESS 189 | } 190 | 191 | fn bindgen() -> ExitCode { 192 | let vitasdk_sys_manifest = vitasdk_sys_manifest(); 193 | let vita_headers = vitasdk_sys_manifest.parent().unwrap().join("vita-headers"); 194 | let output = vitasdk_sys_manifest 195 | .parent() 196 | .unwrap() 197 | .join("src") 198 | .join("bindings.rs"); 199 | let is_build_rs = false; 200 | 201 | vitasdk_sys_build_util::bindgen::generate( 202 | &vita_headers.join("include"), 203 | &vita_headers.join("db"), 204 | &output, 205 | &vitasdk_sys_manifest, 206 | is_build_rs, 207 | ); 208 | 209 | ExitCode::SUCCESS 210 | } 211 | -------------------------------------------------------------------------------- /build-util/src/visitors.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{BTreeMap, BTreeSet}, 3 | mem, 4 | rc::Rc, 5 | }; 6 | 7 | use quote::ToTokens; 8 | use syn::{ 9 | token, visit_mut::VisitMut, AttrStyle, Attribute, ForeignItem, Ident, Item, ItemForeignMod, 10 | MacroDelimiter, Meta, MetaList, 11 | }; 12 | 13 | use crate::vita_headers_db::{stub_lib_name, VitaDb}; 14 | 15 | type FeatureSet = BTreeSet>; 16 | 17 | const DEFINED_ELSEWHERE_FUNCTIONS: [(&str, &str); 3] = [ 18 | // Defined in vitasdk newlib libc implementation 19 | ("vitasdk_get_tls_data", "vitasdk-utils"), 20 | ("vitasdk_get_pthread_data", "vitasdk-utils"), 21 | ("vitasdk_delete_thread_reent", "vitasdk-utils"), 22 | ]; 23 | const DEFINED_ELSEWHERE_VARIABLES: [(&str, &str); 0] = []; 24 | 25 | pub struct Link { 26 | /// link.function[function_name] = stub_library_name 27 | function: BTreeMap>>, 28 | /// link.variable[variable_name] = stub_library_name 29 | variable: BTreeMap>>, 30 | stub_libs: BTreeSet>, 31 | } 32 | 33 | impl Link { 34 | pub fn load(db: &VitaDb) -> Self { 35 | let mut link = Link { 36 | function: DEFINED_ELSEWHERE_FUNCTIONS 37 | .into_iter() 38 | .map(|(func, feat)| (func.into(), BTreeSet::from([Rc::from(feat.to_owned())]))) 39 | .collect(), 40 | variable: DEFINED_ELSEWHERE_VARIABLES 41 | .into_iter() 42 | .map(|(var, feat)| (var.into(), BTreeSet::from([Rc::from(feat.to_owned())]))) 43 | .collect(), 44 | stub_libs: BTreeSet::new(), 45 | }; 46 | 47 | for imports in db.imports_by_firmware.values() { 48 | for (mod_name, mod_data) in &imports.modules { 49 | for (lib_name, lib) in &mod_data.libraries { 50 | let stub_lib_name = stub_lib_name( 51 | mod_name, 52 | lib_name, 53 | lib.stub_name.as_deref(), 54 | lib.kernel, 55 | &imports.firmware, 56 | ) 57 | .to_string(); 58 | let stub_lib_name = link 59 | .stub_libs 60 | .get(stub_lib_name.as_str()) 61 | .cloned() 62 | .unwrap_or_else(|| Rc::from(stub_lib_name)); 63 | 64 | for function_name in lib.function_nids.keys() { 65 | link.function 66 | .entry(function_name.clone()) 67 | .or_default() 68 | .insert(Rc::clone(&stub_lib_name)); 69 | } 70 | 71 | for variable_name in lib.variable_nids.keys() { 72 | link.variable 73 | .entry(variable_name.clone()) 74 | .or_default() 75 | .insert(Rc::clone(&stub_lib_name)); 76 | } 77 | 78 | link.stub_libs.insert(stub_lib_name); 79 | } 80 | } 81 | } 82 | 83 | link 84 | } 85 | 86 | pub fn visit(&self, i: &mut syn::File) { 87 | let mut items_by_features: BTreeMap> = self 88 | .stub_libs 89 | .iter() 90 | .map(|stub_lib_name| (BTreeSet::from([stub_lib_name.clone()]), Vec::new())) 91 | .collect(); 92 | 93 | // Moves mod items to to the "items_by_features" map 94 | i.items = mem::take(&mut i.items) 95 | .into_iter() 96 | .filter_map(|item| { 97 | // We only care about foreign mods 98 | let Item::ForeignMod(foreign_mod) = item else { 99 | return Some(item); 100 | }; 101 | 102 | for foreign_item in foreign_mod.items { 103 | let features: FeatureSet = match &foreign_item { 104 | ForeignItem::Fn(fn_item) => { 105 | let symbol = fn_item.sig.ident.to_string(); 106 | 107 | self.function 108 | .get(&symbol) 109 | .expect("Undefined foreign fn `{symbol}`") 110 | .to_owned() 111 | } 112 | ForeignItem::Static(static_item) => { 113 | let symbol = static_item.ident.to_string(); 114 | 115 | self.variable 116 | .get(&symbol) 117 | .expect("Undefined foreign static `{symbol}`") 118 | .to_owned() 119 | } 120 | _ => panic!("unexpected foreign item: {:?}", foreign_item), 121 | }; 122 | 123 | items_by_features 124 | .entry(features) 125 | .or_default() 126 | .push(foreign_item); 127 | } 128 | 129 | // We'll remove foreign mods for now to re-add them later grouped by feature 130 | None 131 | }) 132 | .collect(); 133 | 134 | i.items 135 | .extend(items_by_features.into_iter().map(|(features, items)| { 136 | let mut foreign_mod: ItemForeignMod = if features.len() == 1 { 137 | let feature = features.first().unwrap(); 138 | syn::parse_quote! { 139 | #[link(name = #feature, kind = "static")] 140 | extern "C" {} 141 | } 142 | } else { 143 | syn::parse_quote! { 144 | extern "C" {} 145 | } 146 | }; 147 | 148 | // Adds feature attributes to mod 149 | if features.len() == 1 { 150 | let feature = features.first(); 151 | foreign_mod 152 | .attrs 153 | .push(syn::parse_quote!(#[cfg(feature = #feature)])); 154 | } else { 155 | let item_idents: Vec<_> = items.iter().map(foreign_item_ident).collect(); 156 | log::warn!( 157 | "Items `{item_idents:?}` are defined in multiple locations: {features:?}" 158 | ); 159 | let feature_gates = || { 160 | features.iter().map(|feature| -> syn::MetaNameValue { 161 | syn::parse_quote!(feature = #feature) 162 | }) 163 | }; 164 | foreign_mod.attrs.push({ 165 | let feature_gates = feature_gates(); 166 | syn::parse_quote!(#[cfg(any(#(#feature_gates),*))]) 167 | }); 168 | } 169 | 170 | // Adds items to mod 171 | foreign_mod.items.extend(items); 172 | 173 | Item::ForeignMod(foreign_mod) 174 | })); 175 | } 176 | } 177 | 178 | pub struct Sort; 179 | 180 | impl VisitMut for Sort { 181 | fn visit_file_mut(&mut self, i: &mut syn::File) { 182 | syn::visit_mut::visit_file_mut(self, i); 183 | 184 | // Sorts items on alphabetical order based on normalized identifier. 185 | // Bindgen items will be moved to the start. 186 | // Note: for simplicity, we rely on sort_by_cached_key being stable and some things 187 | // already being sorted, such as impl blocks already being after their definition. 188 | i.items.sort_by_cached_key(|item| { 189 | let (precedence, ident) = match item { 190 | Item::ExternCrate(i) => (0, i.ident.to_string()), 191 | Item::Use(_i) => (1, String::new()), 192 | Item::Mod(i) => (2, i.ident.to_string()), 193 | Item::Macro(i) => ( 194 | 3, 195 | i.ident 196 | .as_ref() 197 | .map(|i| i.to_string()) 198 | .unwrap_or_else(String::new), 199 | ), 200 | Item::Struct(i) => (4, i.ident.to_string()), 201 | Item::Enum(i) => (4, i.ident.to_string()), 202 | Item::Union(i) => (4, i.ident.to_string()), 203 | Item::Impl(i) => { 204 | let ident = i.self_ty.clone().into_token_stream().to_string(); 205 | (4, ident) 206 | } 207 | Item::Const(i) => (5, i.ident.to_string()), 208 | Item::Static(i) => (6, i.ident.to_string()), 209 | Item::Trait(i) => (7, i.ident.to_string()), 210 | Item::TraitAlias(i) => (8, i.ident.to_string()), 211 | Item::Fn(i) => (8, i.sig.ident.to_string()), 212 | Item::ForeignMod(i) => { 213 | let ident = foreign_mod_ident(i); 214 | 215 | (9, ident) 216 | } 217 | Item::Type(i) => (10, i.ident.to_string()), 218 | i => { 219 | log::warn!("Unexpected item: {i:?}"); 220 | (11, String::new()) 221 | } 222 | }; 223 | consider_bindgen((precedence, normalize_str(&ident))) 224 | }); 225 | } 226 | 227 | fn visit_item_foreign_mod_mut(&mut self, i: &mut ItemForeignMod) { 228 | i.items.sort_by_cached_key(foreign_item_ident); 229 | 230 | syn::visit_mut::visit_item_foreign_mod_mut(self, i) 231 | } 232 | } 233 | 234 | fn foreign_item_ident(foreign_item: &ForeignItem) -> String { 235 | match &foreign_item { 236 | ForeignItem::Fn(i) => i.sig.ident.to_string(), 237 | ForeignItem::Static(i) => i.ident.to_string(), 238 | ForeignItem::Type(i) => i.ident.to_string(), 239 | i => { 240 | log::warn!("Unexpected item in foreign mod: {i:?}"); 241 | String::new() 242 | } 243 | } 244 | } 245 | 246 | /// Gets foreign mod identifier as the feature cfgs concatenated by `+` 247 | fn foreign_mod_ident(foreign_mod: &ItemForeignMod) -> String { 248 | let ident = foreign_mod.attrs.iter().find_map(|attribute| { 249 | if attribute.style != AttrStyle::Outer { 250 | return None; 251 | } 252 | 253 | let Attribute { 254 | pound_token: token::Pound { .. }, 255 | style: AttrStyle::Outer, 256 | bracket_token: token::Bracket { .. }, 257 | meta: 258 | Meta::List(MetaList { 259 | path, 260 | delimiter: MacroDelimiter::Paren(token::Paren { .. }), 261 | tokens, 262 | }), 263 | } = attribute 264 | else { 265 | return None; 266 | }; 267 | 268 | // We're only insterested on `cfg`. 269 | if path.segments.len() != 1 || &path.segments[0].ident != "cfg" { 270 | return None; 271 | } 272 | 273 | let mut token_iter = tokens.clone().into_iter(); 274 | let first_ident: Ident = syn::parse2(token_iter.next()?.into()).ok()?; 275 | if first_ident == "feature" { 276 | let punct: proc_macro2::Punct = syn::parse2(token_iter.next()?.into()).ok()?; 277 | let literal: proc_macro2::Literal = syn::parse2(token_iter.next()?.into()).ok()?; 278 | if token_iter.next().is_some() || punct.as_char() != '=' { 279 | return None; 280 | } 281 | Some( 282 | literal 283 | .to_string() 284 | .strip_prefix('"')? 285 | .strip_suffix('"')? 286 | .to_owned(), 287 | ) 288 | } else if first_ident == "any" { 289 | let group: proc_macro2::Group = syn::parse2(token_iter.next()?.into()).ok()?; 290 | if token_iter.next().is_some() { 291 | return None; 292 | } 293 | 294 | enum Step { 295 | Ident, 296 | Equals, 297 | Literal, 298 | Separator, 299 | } 300 | 301 | let (features, _) = group.stream().into_iter().try_fold( 302 | (Vec::new(), Step::Ident), 303 | |(mut acc, step), token| match step { 304 | Step::Ident => { 305 | if syn::parse2::(token.into()).ok()? != "feature" { 306 | return None; 307 | } 308 | Some((acc, Step::Equals)) 309 | } 310 | Step::Equals => { 311 | if syn::parse2::(token.into()) 312 | .ok()? 313 | .as_char() 314 | != '=' 315 | { 316 | return None; 317 | } 318 | Some((acc, Step::Literal)) 319 | } 320 | Step::Literal => { 321 | let literal: proc_macro2::Literal = syn::parse2(token.into()).ok()?; 322 | acc.push( 323 | literal 324 | .to_string() 325 | .strip_prefix('"')? 326 | .strip_suffix('"')? 327 | .to_owned(), 328 | ); 329 | Some((acc, Step::Separator)) 330 | } 331 | Step::Separator => { 332 | if syn::parse2::(token.into()) 333 | .ok()? 334 | .as_char() 335 | != ',' 336 | { 337 | return None; 338 | } 339 | Some((acc, Step::Ident)) 340 | } 341 | }, 342 | )?; 343 | 344 | features.into_iter().reduce(|acc, f| acc + "+" + &f) 345 | } else { 346 | None 347 | } 348 | }); 349 | 350 | ident.unwrap_or_else(String::new) 351 | } 352 | 353 | fn normalize_str(input: &str) -> String { 354 | input.to_lowercase().replace('_', "") 355 | } 356 | 357 | fn consider_bindgen(keys: (i32, String)) -> (i32, String) { 358 | let (precedence, ident) = keys; 359 | let new_precedence = if ident.starts_with("bindgen") { 360 | // Move bindgen items to the start of the file 361 | precedence - 16 362 | } else { 363 | precedence 364 | }; 365 | (new_precedence, ident) 366 | } 367 | -------------------------------------------------------------------------------- /build-util/src/vita_headers_db.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{btree_map, BTreeMap, BTreeSet, HashSet}, 3 | fmt, fs, 4 | io::{self, Read, Seek, Write}, 5 | mem, 6 | path::{Path, PathBuf}, 7 | }; 8 | 9 | use serde::Deserialize; 10 | 11 | /// Blacklisted stub libs containing conflicting symbol definitions. 12 | const CONFLICTING_STUB_LIBS: [&str; 4] = [ 13 | // Defines `__aeabi_uidiv`, which is also defined by compiler_builtins. 14 | "SceSysclibForDriver_stub", 15 | // Defines `__aeabi_unwind_cpp_pr0` and probably other symbols that seem 16 | // to collide with std. 17 | "SceLibc_stub", 18 | // This one overrides pthread_getspecific and friends, which makes the app 19 | // crash when using thread locals... 20 | "SceLibMonoBridge_stub", 21 | // Conflicts with compiler_builtins 22 | "SceRtabi_stub", 23 | ]; 24 | 25 | #[derive(Default)] 26 | pub struct VitaDb { 27 | pub imports_by_firmware: BTreeMap, 28 | } 29 | 30 | impl VitaDb { 31 | pub fn load(db: &Path) -> Self { 32 | let mut out = VitaDb { 33 | imports_by_firmware: BTreeMap::new(), 34 | }; 35 | 36 | for version_dir in db.read_dir().unwrap() { 37 | for yml in version_dir.unwrap().path().read_dir().unwrap() { 38 | let yml = yml.unwrap().path(); 39 | log::debug!("Loading: {}", yml.display()); 40 | let rdr = io::BufReader::new(fs::File::open(yml).unwrap()); 41 | out.add_imports(serde_yaml::from_reader(rdr).unwrap()); 42 | } 43 | } 44 | 45 | out 46 | } 47 | 48 | pub fn split_conflicting(&mut self) -> Self { 49 | self.split_filter(|imports, mod_name, _, lib_name, lib| { 50 | let stub_lib = stub_lib_name( 51 | mod_name, 52 | lib_name, 53 | lib.stub_name.as_deref(), 54 | lib.kernel, 55 | &imports.firmware, 56 | ) 57 | .to_string(); 58 | CONFLICTING_STUB_LIBS.contains(&stub_lib.as_str()) 59 | }) 60 | } 61 | 62 | pub fn split_kernel(&mut self) -> Self { 63 | self.split_filter(|_, _, _, _, lib| lib.kernel) 64 | } 65 | 66 | fn split_filter(&mut self, mut f: F) -> Self 67 | where 68 | F: FnMut(&VitaImports, &str, &VitaImportsModule, &str, &VitaImportsLib) -> bool, 69 | { 70 | let mut split = VitaDb::default(); 71 | self.imports_by_firmware.retain(|_, imports| { 72 | split.add_imports(imports.split_filter(&mut f)); 73 | !imports.is_empty() 74 | }); 75 | split 76 | } 77 | 78 | pub fn stub_lib_names(&self) -> impl Iterator + '_ { 79 | self.imports_by_firmware.values().flat_map(|imports| { 80 | imports.modules.iter().flat_map(|(module_name, module)| { 81 | module.libraries.iter().map(|(lib_name, lib)| { 82 | stub_lib_name( 83 | module_name, 84 | lib_name, 85 | lib.stub_name.as_deref(), 86 | lib.kernel, 87 | &imports.firmware, 88 | ) 89 | .to_string() 90 | }) 91 | }) 92 | }) 93 | } 94 | 95 | pub fn add_imports(&mut self, imports: VitaImports) { 96 | if imports.is_empty() { 97 | return; 98 | } 99 | let entry = self.imports_by_firmware.entry(imports.firmware.clone()); 100 | match entry { 101 | btree_map::Entry::Occupied(o) => o.into_mut().merge_from(imports), 102 | btree_map::Entry::Vacant(v) => { 103 | v.insert(imports); 104 | } 105 | } 106 | } 107 | 108 | pub fn update_manifest_features(&self, vitasdk_sys_manifest: &Path) { 109 | const FEATURES_MARKER: &str = "# Automatically generated by build-util:"; 110 | 111 | let mut manifest = fs::OpenOptions::new() 112 | .read(true) 113 | .write(true) 114 | .open(vitasdk_sys_manifest) 115 | .expect("unable to open manifest"); 116 | 117 | let marker_position = { 118 | let mut manifest_string = String::new(); 119 | manifest 120 | .read_to_string(&mut manifest_string) 121 | .expect("unable to read manifest"); 122 | 123 | manifest_string 124 | .find(FEATURES_MARKER) 125 | .expect("features marker not found in manifest") 126 | }; 127 | 128 | manifest 129 | .seek(io::SeekFrom::Start(u64::try_from(marker_position).unwrap())) 130 | .expect("unable to seek manifest"); 131 | 132 | writeln!(manifest, "{}", FEATURES_MARKER).expect("unable to write to manifest"); 133 | 134 | let stub_libs: BTreeSet<_> = self.stub_lib_names().collect(); 135 | 136 | write_all_stubs_feature(&mut manifest, &stub_libs).expect("unable to write to manifest"); 137 | write_stub_features(&mut manifest, &stub_libs).expect("unable to write to manifest"); 138 | 139 | let stream_position = manifest 140 | .stream_position() 141 | .expect("unable to get current stream position"); 142 | manifest 143 | .set_len(stream_position) 144 | .expect("unable update manifest length"); 145 | } 146 | 147 | pub fn check_missing_manifest_features(&self, vitasdk_sys_manifest: &Path) { 148 | let predicate = missing_features_filter(vitasdk_sys_manifest); 149 | let missing_features: Vec<_> = self.stub_lib_names().filter(predicate).collect(); 150 | log::warn!("Missing features: {missing_features:#?}\nIf you need any of those features, please open an issue so we can update vitasdk-sys."); 151 | } 152 | } 153 | 154 | pub fn missing_features_filter(vitasdk_sys_manifest: &Path) -> impl FnMut(&String) -> bool { 155 | #[derive(serde::Deserialize)] 156 | struct CargoManifest { 157 | #[serde(default)] 158 | features: Features, 159 | } 160 | 161 | #[derive(Default, serde::Deserialize)] 162 | struct Features { 163 | #[serde(default, rename = "all-stubs")] 164 | all_stubs: Vec, 165 | } 166 | 167 | let manifest = 168 | fs::read_to_string(vitasdk_sys_manifest).expect("Unable to load vitasdk's Cargo.toml"); 169 | let manifest: CargoManifest = 170 | toml::from_str(&manifest).expect("Unable to parse vitasdk's Cargo.toml"); 171 | let stubs: HashSet<_> = manifest.features.all_stubs.into_iter().collect(); 172 | 173 | move |stub_lib| !stubs.contains(stub_lib) 174 | } 175 | 176 | pub fn missing_libs_filter() -> impl FnMut(&String) -> bool { 177 | let lib_dir = PathBuf::from(std::env::var_os("VITASDK").unwrap()).join("arm-vita-eabi/lib"); 178 | assert!(lib_dir.is_dir()); 179 | move |stub_lib| !lib_dir.join(format!("lib{stub_lib}.a")).exists() 180 | } 181 | 182 | #[derive(Deserialize)] 183 | pub struct VitaImports { 184 | pub version: i32, 185 | pub firmware: String, 186 | pub modules: BTreeMap, 187 | } 188 | 189 | impl VitaImports { 190 | pub fn clone_emptied(&self) -> Self { 191 | VitaImports { 192 | version: self.version, 193 | firmware: self.firmware.clone(), 194 | modules: BTreeMap::new(), 195 | } 196 | } 197 | 198 | pub fn take(&mut self) -> Self { 199 | let empty = self.clone_emptied(); 200 | mem::replace(self, empty) 201 | } 202 | 203 | pub fn is_empty(&self) -> bool { 204 | self.modules.is_empty() 205 | } 206 | 207 | pub fn add_module>(&mut self, name: S, module: VitaImportsModule) { 208 | if !module.is_empty() { 209 | let old = self.modules.insert(name.into(), module); 210 | assert!(old.is_none()); 211 | } 212 | } 213 | 214 | pub fn merge_from(&mut self, other: Self) { 215 | assert_eq!(self.version, other.version); 216 | assert_eq!(self.firmware, other.firmware); 217 | self.modules.extend(other.modules); 218 | } 219 | 220 | fn split_filter(&mut self, mut f: F) -> Self 221 | where 222 | F: FnMut(&VitaImports, &str, &VitaImportsModule, &str, &VitaImportsLib) -> bool, 223 | { 224 | let empty = self.clone_emptied(); 225 | let mut split = self.clone_emptied(); 226 | self.modules.retain(|module_name, module| { 227 | split.add_module( 228 | module_name, 229 | module.split_filter(|module, lib_name, lib| { 230 | f(&empty, module_name, module, lib_name, lib) 231 | }), 232 | ); 233 | !module.is_empty() 234 | }); 235 | split 236 | } 237 | } 238 | 239 | #[derive(Deserialize)] 240 | pub struct VitaImportsModule { 241 | pub nid: u32, 242 | pub libraries: BTreeMap, 243 | } 244 | 245 | impl VitaImportsModule { 246 | pub fn clone_emptied(&self) -> Self { 247 | VitaImportsModule { 248 | nid: self.nid, 249 | libraries: BTreeMap::new(), 250 | } 251 | } 252 | 253 | pub fn take(&mut self) -> Self { 254 | let empty = self.clone_emptied(); 255 | mem::replace(self, empty) 256 | } 257 | 258 | pub fn add_lib>(&mut self, name: S, lib: VitaImportsLib) { 259 | if !lib.is_empty() { 260 | let old = self.libraries.insert(name.into(), lib); 261 | assert!(old.is_none()); 262 | } 263 | } 264 | 265 | pub fn is_empty(&self) -> bool { 266 | self.libraries.is_empty() 267 | } 268 | 269 | fn split_filter(&mut self, mut f: F) -> Self 270 | where 271 | F: FnMut(&VitaImportsModule, &str, &VitaImportsLib) -> bool, 272 | { 273 | let empty = self.clone_emptied(); 274 | let mut split = self.clone_emptied(); 275 | self.libraries.retain(|lib_name, lib| { 276 | split.add_lib(lib_name, lib.split_filter(|lib| f(&empty, lib_name, lib))); 277 | !lib.is_empty() 278 | }); 279 | split 280 | } 281 | } 282 | 283 | #[derive(Deserialize)] 284 | pub struct VitaImportsLib { 285 | pub kernel: bool, 286 | pub nid: u32, 287 | pub version: Option, 288 | #[serde(rename = "stubname", default)] 289 | pub stub_name: Option, 290 | #[serde(rename = "functions", default)] 291 | pub function_nids: BTreeMap, 292 | #[serde(rename = "variables", default)] 293 | pub variable_nids: BTreeMap, 294 | } 295 | 296 | impl VitaImportsLib { 297 | fn clone_emptied(&self) -> Self { 298 | VitaImportsLib { 299 | kernel: self.kernel, 300 | nid: self.nid, 301 | version: self.version, 302 | stub_name: self.stub_name.clone(), 303 | function_nids: BTreeMap::new(), 304 | variable_nids: BTreeMap::new(), 305 | } 306 | } 307 | 308 | pub fn take(&mut self) -> Self { 309 | let empty = self.clone_emptied(); 310 | mem::replace(self, empty) 311 | } 312 | 313 | pub fn is_empty(&self) -> bool { 314 | self.function_nids.is_empty() && self.variable_nids.is_empty() 315 | } 316 | 317 | fn split_filter(&mut self, mut f: F) -> Self 318 | where 319 | F: FnMut(&VitaImportsLib) -> bool, 320 | { 321 | let mut split = self.clone_emptied(); 322 | if f(self) { 323 | mem::swap(self, &mut split); 324 | } 325 | split 326 | } 327 | } 328 | 329 | pub(crate) fn stub_lib_name<'a>( 330 | mod_name: &'a str, 331 | lib_name: &'a str, 332 | stub_name: Option<&'a str>, 333 | kernel: bool, 334 | firmware: &'a str, 335 | ) -> impl fmt::Display + 'a { 336 | struct StubLibName<'a> { 337 | name: &'a str, 338 | firmware: &'a str, 339 | } 340 | 341 | impl fmt::Display for StubLibName<'_> { 342 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 343 | f.write_str(self.name)?; 344 | if self.firmware != "3.60" { 345 | f.write_str("_")?; 346 | self.firmware.split('.').try_for_each(|s| f.write_str(s))?; 347 | } 348 | f.write_str("_stub") 349 | } 350 | } 351 | 352 | if let Some(stubname) = stub_name { 353 | StubLibName { 354 | name: stubname, 355 | firmware, 356 | } 357 | } else if kernel { 358 | StubLibName { 359 | name: lib_name, 360 | firmware, 361 | } 362 | } else { 363 | StubLibName { 364 | name: mod_name, 365 | firmware, 366 | } 367 | } 368 | } 369 | 370 | fn write_all_stubs_feature(sink: &mut dyn Write, stub_libs: &BTreeSet) -> io::Result<()> { 371 | writeln!(sink, "all-stubs = [")?; 372 | 373 | for stub_lib in stub_libs 374 | .iter() 375 | .filter(|stub_lib| !CONFLICTING_STUB_LIBS.contains(&stub_lib.as_str())) 376 | { 377 | writeln!(sink, " \"{stub_lib}\",")?; 378 | } 379 | 380 | writeln!(sink, "]") 381 | } 382 | 383 | fn write_stub_features(sink: &mut dyn Write, stub_libs: &BTreeSet) -> io::Result<()> { 384 | for stub_lib in stub_libs { 385 | writeln!(sink, "{stub_lib} = []")?; 386 | } 387 | Ok(()) 388 | } 389 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | 4 | fn main() { 5 | #[cfg(feature = "log-build")] 6 | env_logger::init(); 7 | 8 | println!("cargo:rerun-if-env-changed=DOCS_RS"); 9 | if std::env::var("DOCS_RS").is_ok() { 10 | return; 11 | } 12 | 13 | println!("cargo:rerun-if-env-changed=VITASDK"); 14 | let vitasdk = match env::var("VITASDK") { 15 | Ok(vitasdk) => { 16 | let vitasdk = PathBuf::from(vitasdk); 17 | let sysroot = vitasdk.join("arm-vita-eabi"); 18 | 19 | assert!( 20 | sysroot.exists(), 21 | "VITASDK's sysroot does not exist, please install or update vitasdk first" 22 | ); 23 | 24 | let lib = sysroot.join("lib"); 25 | assert!(lib.exists(), "VITASDK's `lib` directory does not exist"); 26 | println!("cargo:rustc-link-search=native={}", lib.to_str().unwrap()); 27 | 28 | vitasdk 29 | } 30 | Err(env::VarError::NotPresent) => { 31 | panic!("VITASDK env var is not set") 32 | } 33 | Err(env::VarError::NotUnicode(s)) => { 34 | panic!("VITASDK env var is not a valid unicode but got: {s:?}") 35 | } 36 | }; 37 | 38 | // Just to mark it as used 39 | #[cfg(not(feature = "bindgen"))] 40 | let _ = vitasdk; 41 | 42 | #[cfg(feature = "bindgen")] 43 | { 44 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); 45 | let bindings_output = out_dir.join("bindings.rs"); 46 | 47 | let vita_headers_include = vitasdk.join("arm-vita-eabi").join("include"); 48 | let db = vitasdk.join("share").join("vita-headers").join("db"); 49 | assert!( 50 | vita_headers_include.exists(), 51 | "VITASDK's `include` directory does not exist" 52 | ); 53 | assert!(db.exists(), "VITASDK's `db` directory does not exist"); 54 | 55 | let is_build_rs = true; 56 | 57 | vitasdk_sys_build_util::bindgen::generate( 58 | &vita_headers_include, 59 | &db, 60 | &bindings_output, 61 | &vitasdk_sys_manifest(), 62 | is_build_rs, 63 | ); 64 | } 65 | } 66 | 67 | #[cfg(feature = "bindgen")] 68 | fn vitasdk_sys_manifest() -> PathBuf { 69 | PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml") 70 | } 71 | -------------------------------------------------------------------------------- /headers/all.h: -------------------------------------------------------------------------------- 1 | #include "vitasdk.h" 2 | #include "vitasdkkern.h" 3 | -------------------------------------------------------------------------------- /headers/time.h: -------------------------------------------------------------------------------- 1 | typedef long time_t; 2 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 2 | #![no_std] 3 | #![allow( 4 | nonstandard_style, 5 | clippy::useless_transmute, 6 | clippy::missing_safety_doc, 7 | clippy::too_many_arguments, 8 | clippy::len_without_is_empty 9 | )] 10 | 11 | mod ctypes { 12 | pub use ::core::ffi::c_void; 13 | 14 | pub type c_char = i8; 15 | pub type c_double = f64; 16 | pub type c_float = f32; 17 | pub type c_int = i32; 18 | pub type c_long = i32; 19 | pub type c_longlong = i64; 20 | pub type c_schar = i8; 21 | pub type c_short = i16; 22 | pub type c_uchar = u8; 23 | pub type c_uint = u32; 24 | pub type c_ulong = u32; 25 | pub type c_ulonglong = u64; 26 | pub type c_ushort = u16; 27 | } 28 | 29 | pub use ctypes::*; 30 | 31 | #[cfg(test)] 32 | mod tests; 33 | 34 | #[cfg(any(not(feature = "bindgen"), docsrs))] 35 | include!("bindings.rs"); 36 | 37 | #[cfg(all(feature = "bindgen", not(docsrs)))] 38 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 39 | -------------------------------------------------------------------------------- /src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod sce_clib; 2 | -------------------------------------------------------------------------------- /src/tests/sce_clib.rs: -------------------------------------------------------------------------------- 1 | use crate::{sceClibStrncmp, sceClibTolower, sceClibToupper}; 2 | 3 | #[test] 4 | fn tolower() { 5 | unsafe { 6 | assert_eq!(sceClibTolower(b'a' as i8), b'a' as i32); 7 | assert_eq!(sceClibTolower(b'A' as i8), b'a' as i32); 8 | assert_eq!(sceClibTolower(b'Z' as i8), b'z' as i32); 9 | assert_eq!(sceClibTolower(b';' as i8), b';' as i32); 10 | assert_eq!(sceClibTolower(b'\n' as i8), b'\n' as i32); 11 | assert_eq!(sceClibTolower(b'\0' as i8), b'\0' as i32); 12 | } 13 | } 14 | 15 | #[test] 16 | fn toupper() { 17 | unsafe { 18 | assert_eq!(sceClibToupper(b'A' as i8), b'A' as i32); 19 | assert_eq!(sceClibToupper(b'a' as i8), b'A' as i32); 20 | assert_eq!(sceClibToupper(b'Z' as i8), b'Z' as i32); 21 | assert_eq!(sceClibToupper(b';' as i8), b';' as i32); 22 | assert_eq!(sceClibToupper(b'\n' as i8), b'\n' as i32); 23 | assert_eq!(sceClibToupper(b'\0' as i8), b'\0' as i32); 24 | } 25 | } 26 | 27 | #[test] 28 | fn strncmp() { 29 | let reference = "Much doge, wow!"; 30 | 31 | unsafe { 32 | assert_eq!( 33 | sceClibStrncmp( 34 | reference.as_ptr() as *const i8, 35 | "Much doge, wow!".as_ptr() as *const i8, 36 | 15 37 | ), 38 | 0 39 | ); 40 | assert_eq!( 41 | sceClibStrncmp( 42 | reference.as_ptr() as *const i8, 43 | "Much".as_ptr() as *const i8, 44 | 4 45 | ), 46 | 0 47 | ); 48 | assert!( 49 | sceClibStrncmp( 50 | reference.as_ptr() as *const i8, 51 | "much".as_ptr() as *const i8, 52 | 4 53 | ) < 0 54 | ); 55 | assert!( 56 | sceClibStrncmp( 57 | reference.as_ptr() as *const i8, 58 | "MUCH".as_ptr() as *const i8, 59 | 4 60 | ) > 0 61 | ); 62 | } 63 | } 64 | --------------------------------------------------------------------------------