# How to Update shadps4-emu Dependencies: Managing Git Submodules and CMake FetchContent

> Learn how to update shadps4-emu dependencies by managing Git submodules and reconfiguring CMake FetchContent for the latest library versions. Keep your build current.

- Repository: [shadps4-emu/shadPS4](https://github.com/shadps4-emu/shadPS4)
- Tags: how-to-guide
- Published: 2026-03-19

---

**Updating shadps4-emu dependencies requires synchronizing Git submodules located in the `externals/` directory and reconfiguring the CMake build system to recognize new library versions.**

The shadPS4 PlayStation 4 emulator manages its third-party code primarily through Git submodules, with one exception handled via CMake's `FetchContent` module. Whether you are building from source for development or pulling recent changes, keeping these dependencies synchronized prevents build failures and ensures access to the latest upstream fixes.

## Understanding the Dependency Architecture

According to the shadps4-emu/shadPS4 source code, the project stores almost all third-party libraries as Git submodules under the `externals/` path. The **`.gitmodules`** file at the repository root defines each submodule's URL, local path, and shallow clone settings. The only dependency not managed as a submodule is **Z-lib**, which the project fetches via CMake's `FetchContent` declarative API defined in [`externals/CMakeLists.txt`](https://github.com/shadps4-emu/shadPS4/blob/main/externals/CMakeLists.txt) at lines 47-53.

The root **[`CMakeLists.txt`](https://github.com/shadps4-emu/shadPS4/blob/main/CMakeLists.txt)** integrates these dependencies into the build by calling `add_subdirectory()` on the `externals/` directory, making proper submodule initialization critical for compilation.

## Initial Clone with Dependencies

Before updating, ensure your local repository includes all submodules. If you have not yet cloned the repository, use the recursive flag to fetch every dependency immediately:

```bash
git clone --recursive https://github.com/shadps4-emu/shadPS4.git
cd shadPS4

```

If you previously cloned without the `--recursive` flag, initialize the submodules manually:

```bash
git submodule update --init --recursive

```

## Step-by-Step Dependency Update Workflow

### 1. Synchronize Submodule URLs

When the upstream `.gitmodules` file changes—adding new dependencies or updating repository URLs—you must synchronize your local configuration:

```bash
git submodule sync

```

This updates the `.git/config` entries to match the remote's `.gitmodules` definitions.

### 2. Update to Recorded Commits

To checkout the exact dependency versions referenced by the current commit of the main repository (the safest update method), run:

```bash
git submodule update --init --recursive

```

This command updates each submodule to the specific commit hash recorded in the super-project's index, ensuring a reproducible build matching the upstream CI configuration.

### 3. Upgrade Individual Dependencies

To pull newer upstream changes for a specific library—such as the `fmt` formatting library—navigate into the submodule directory and fetch directly:

```bash
cd externals/fmt
git fetch origin
git checkout main
git pull
cd ../../
git add externals/fmt
git commit -m "Update fmt to latest"

```

Repeat this pattern for any specific `externals/<library>` directory you wish to advance beyond the pinned commit.

### 4. Bulk Update All Dependencies

To advance every submodule to the tip of its default branch simultaneously (useful for testing bleeding-edge compatibility):

```bash
git submodule foreach 'git checkout $(git rev-parse --abbrev-ref HEAD); git pull'
git add externals/*
git commit -m "Upgrade all third-party dependencies"

```

**Warning:** Bulk updates may introduce breaking API changes. Always perform a clean build after executing this workflow to verify compatibility.

## Reconfiguring the CMake Build

After updating submodules, regenerate the build cache so CMake detects new headers, library paths, and version changes:

```bash
cmake -S . -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build build --parallel$(nproc)

```

Skipping this reconfiguration step often results in linker errors or missing symbol definitions because CMake caches the previous dependency locations.

## Managing the FetchContent Exception (Z-lib)

Unlike other dependencies, **Z-lib** is not a Git submodule. The project declares this dependency in [`externals/CMakeLists.txt`](https://github.com/shadps4-emu/shadPS4/blob/main/externals/CMakeLists.txt) using `FetchContent_Declare`. To update Z-lib to a newer release:

1. Edit the `FetchContent_Declare` block in [`externals/CMakeLists.txt`](https://github.com/shadps4-emu/shadPS4/blob/main/externals/CMakeLists.txt)
2. Modify the `GIT_TAG` or `URL` parameter to point to the desired version
3. Delete the existing build directory to clear the CMake cache
4. Re-run the CMake configuration command

This mechanism downloads and builds Z-lib during the configuration phase, separate from the submodule workflow.

## Summary

- **Git submodules** in the `externals/` directory manage the majority of shadps4-emu dependencies, controlled via the `.gitmodules` file
- Use **`git submodule update --init --recursive`** to synchronize with the upstream project's pinned dependency versions
- Use **`git submodule foreach`** with `git pull` to bulk-update all libraries to their latest branch heads, though this risks API breakage
- Always **reconfigure CMake** after dependency updates to regenerate build files with new library paths
- **Z-lib** is the sole exception, managed via CMake `FetchContent` in [`externals/CMakeLists.txt`](https://github.com/shadps4-emu/shadPS4/blob/main/externals/CMakeLists.txt) rather than as a submodule

## Frequently Asked Questions

### Why does my build fail after updating dependencies?

Build failures typically occur when CMake retains cached references to old submodule paths or when a bulk update introduced incompatible API changes. Resolve this by deleting your build directory (`rm -rf build/`) and reconfiguring from scratch with `cmake -S . -B build`. This forces CMake to redetect all `externals/` directories and recompile against the updated headers.

### How do I update only one specific dependency?

Navigate into the specific submodule directory (e.g., `cd externals/sdl2`), checkout the target branch, pull the latest changes, then return to the repository root to stage and commit the submodule pointer update. This targeted approach isolates changes and simplifies debugging compared to bulk updates.

### What is the difference between `git submodule update` and pulling inside the submodule?

`git submodule update --init --recursive` checks out the exact commit hash recorded in the main repository's index, ensuring a reproducible build. Conversely, entering a submodule and running `git pull` fetches the latest upstream commit on the current branch, which may differ from the version the shadPS4 maintainers have tested and pinned.

### How do I add a new third-party library to the project?

New dependencies require editing the **`.gitmodules`** file to add the submodule entry, running `git submodule add <url> externals/<name>`, and updating [`externals/CMakeLists.txt`](https://github.com/shadps4-emu/shadPS4/blob/main/externals/CMakeLists.txt) to include the new directory via `add_subdirectory()` if it is not header-only. This pattern follows the existing architecture used for libraries like `fmt` and `zlib-ng`.