Optimizing Docc Static Hosting Build

We are currently building our iOS app DocC static-hosted documentation using Github CI and Github Pages.

The build and deployment take about 55 minutes and involve multiple steps. We're combining multiple modules' documentation into a single site/archive, but it's unclear if we're going about this in the right way.

Are there any tips for speeding this up? Are all the following steps necessary, or any flags we can add to optimize?

name: Deploy DocC
'on':
  schedule:
    - cron: '0 0,12 * * *'
  workflow_dispatch: null
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: macos-15-xlarge
    env:
      MODULES_DIR: "./Modules"
      DERIVED_DATA: "./tmp/docbuild"
      SYMBOL_GRAPHS_DIR: "./tmp/symbol-graphs"
      ARCHIVES_DIR: "./tmp/doccarchives"
      MERGED_DOCC_ARCHIVE: "./MergedDocs.doccarchive"
      STATIC_OUTPUT_DIR: "./docs"
      PACKAGE_JSON: "./tmp/package.json"
      SWIFT_DOCC: "./swift-docc/.build/debug/docc"
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.ref }}
          fetch-depth: 0
          lfs: true

      - name: Prepare signing certificates
        env:
         REDACTED

      - name: Install Swift-DocC
        run: |
          git clone https://github.com/apple/swift-docc.git
          cd swift-docc
          swift build
          cd ..

      - name: Install current Bash on macOS
        run: |
          brew install bash
          echo "Using Bash version: $(bash --version | head -n1)"

      - name: Set up directories for documentation
        run: |
          rm -rf "${ARCHIVES_DIR}" "${MERGED_DOCC_ARCHIVE}" "${STATIC_OUTPUT_DIR}" "${SYMBOL_GRAPHS_DIR}"
          mkdir -p "${ARCHIVES_DIR}" "${STATIC_OUTPUT_DIR}" "${SYMBOL_GRAPHS_DIR}"

      - name: Generate package.json
        run: |
          echo "๐Ÿ“ฆ Generating package.json from Package.swift..."
          if [ ! -f "${MODULES_DIR}/Package.swift" ]; then
              echo "โŒ Error: Package.swift not found in ${MODULES_DIR}"
              exit 1
          fi
          (cd "${MODULES_DIR}" && swift package describe --type json) > "${PACKAGE_JSON}"

      - name: Validate package.json
        run: |
          if [ ! -f "${PACKAGE_JSON}" ]; then
              echo "โŒ Error: Failed to generate package.json"
              exit 1
          fi
          echo "โœ… package.json generated successfully"

      - name: Build with symbol graphs
        run: |
          xcodebuild -parallelizeTargets docbuild \
            -project ProjectName.xcodeproj \
            -scheme ProjectScheme \
            -derivedDataPath "${DERIVED_DATA}" \
            -destination 'generic/platform=iOS' \
            ENABLE_SYMBOL_GRAPHS=YES \
            CODE_SIGN_STYLE=Manual

      - name: Copy symbol graphs
        run: |
          set -e
          shopt -s nullglob globstar

          TARGETS=$(jq -r '
            .targets[]? | 
            select(.type == "library" or .type == "executable") | 
            .name' "${PACKAGE_JSON}")

          if [[ -z "$TARGETS" ]]; then
              echo "โŒ No targets found in package.json."
              exit 1
          fi

          echo "๐ŸŽฏ Targets found: $TARGETS"

          # Create an associative array for dependencies (Bash 5+)
          declare -A TARGET_DEPENDENCIES
          declare -A TARGET_ARCHIVES

          # Extract dependencies for each target
          while read -r TARGET; do
              echo "๐Ÿ“š Processing target: $TARGET"
              DEPENDENCIES=$(jq -r --arg TARGET "$TARGET" '
                .targets[]? |
                select(.name == $TARGET) |
                .target_dependencies?[]?' "$PACKAGE_JSON")

              # Handle null case for dependencies
              if [[ -n "$DEPENDENCIES" ]]; then
                  TARGET_DEPENDENCIES["$TARGET"]="$DEPENDENCIES"
              else
                  echo "โš ๏ธ No dependencies found for target: $TARGET"
              fi
          done <<< "$TARGETS"

          # Print extracted dependencies for debugging
          echo "โœ… Targets and their dependencies:"
          for TARGET in "${!TARGET_DEPENDENCIES[@]}"; do
              echo "๐Ÿ”— $TARGET depends on: ${TARGET_DEPENDENCIES[$TARGET]}"
          done

          for TARGET in $TARGETS; do
              TARGET_SYMBOL_GRAPHS_DIR="${SYMBOL_GRAPHS_DIR}/${TARGET}"
              mkdir -p "$TARGET_SYMBOL_GRAPHS_DIR"
              XCODE_SYMBOL_GRAPH_DIR_IOS="${DERIVED_DATA}/Build/Intermediates.noindex/ProjectNameModules.build/Debug-iphoneos/${TARGET}.build/symbol-graph"
              if [ -d "$XCODE_SYMBOL_GRAPH_DIR_IOS" ]; then
                  cp -R "${XCODE_SYMBOL_GRAPH_DIR_IOS}"
              fi
          done

          echo "๐Ÿ—๏ธ Start Converting documentation for each target..."

          for TARGET in $TARGETS; do
              DOCC_CATALOG=""
              while IFS= read -r -d '' docc_dir; do
                  DOCC_CATALOG="$docc_dir"
                  echo "๐Ÿ“š Found documentation catalog: $DOCC_CATALOG"
                  break  # Take the first one found
              done < <(find "${MODULES_DIR}/Sources/${TARGET}" -type d -name "*.docc" -print0)

              TARGET_SYMBOL_GRAPHS_DIR="${SYMBOL_GRAPHS_DIR}/${TARGET}"
              
              # Skip if no docc catalog AND no symbol graphs
              if [[ -z "$DOCC_CATALOG" ]] && [[ -z "$(ls -A "$TARGET_SYMBOL_GRAPHS_DIR")" ]]; then
                  echo "โš ๏ธ Skipping $TARGET - No documentation catalog or symbol graphs."
                  continue
              fi

              echo "๐Ÿ”จ Building documentation for target: $TARGET"
              echo "Symbol graphs directory: $TARGET_SYMBOL_GRAPHS_DIR"
              echo "Contents of symbol graphs directory:"
              ls -la "$TARGET_SYMBOL_GRAPHS_DIR"

              DEPENDENCY_FLAGS=()
              for DEP in ${TARGET_DEPENDENCIES["$TARGET"]}; do
                  if [[ -n "${TARGET_ARCHIVES[$DEP]}" ]]; then
                      echo "๐Ÿ”— Adding dependency on ${TARGET_ARCHIVES[$DEP]}"
                      DEPENDENCY_FLAGS+=(--dependency "${TARGET_ARCHIVES[$DEP]}")
                  fi
              done

              ARCHIVE_PATH="${ARCHIVES_DIR}/${TARGET}.doccarchive"
              
              # Add symbol graphs to convert command if they exist
              SYMBOL_GRAPH_FLAGS=()
              if [[ -n "$(ls -A "$TARGET_SYMBOL_GRAPHS_DIR")" ]]; then
                  SYMBOL_GRAPH_FLAGS+=(--additional-symbol-graph-dir "$TARGET_SYMBOL_GRAPHS_DIR")
              fi

              # Build docc convert command based on what's available
              CONVERT_ARGS=()
              if [[ -n "$DOCC_CATALOG" ]]; then
                  CONVERT_ARGS+=("$DOCC_CATALOG")
                  echo "Using .docc catalog: $DOCC_CATALOG"
                  echo "Contents of .docc catalog:"
                  ls -la "$DOCC_CATALOG"
              else
                  echo "No .docc catalog found, using symbol graphs only"
              fi
              
              CONVERT_ARGS+=(
                  --fallback-display-name "$TARGET"
                  --fallback-bundle-identifier "com.example.${TARGET}"
                  --fallback-bundle-version "1.0.0"
                  --output-path "$ARCHIVE_PATH"
                  "${DEPENDENCY_FLAGS[@]}"
                  "${SYMBOL_GRAPH_FLAGS[@]}"
                  --emit-digest
                  --enable-experimental-external-link-support
                  --enable-experimental-overloaded-symbol-presentation
                  --enable-experimental-mentioned-in
                  --hosting-base-path "$TARGET"
                  --no-transform-for-static-hosting
              )

              echo "Running command: $SWIFT_DOCC convert ${CONVERT_ARGS[*]}"

              if ! "$SWIFT_DOCC" convert "${CONVERT_ARGS[@]}" 2>docc_error_${TARGET}.log; then
                  echo "โŒ Failed to convert documentation for $TARGET"
                  echo "Error output:"
                  cat docc_error_${TARGET}.log
                  echo "Symbol graphs contents:"
                  ls -la "$TARGET_SYMBOL_GRAPHS_DIR"
                  if [[ -n "$DOCC_CATALOG" ]]; then
                      echo ".docc catalog contents:"
                      ls -la "$DOCC_CATALOG"
                  fi
                  exit 1
              fi

              echo "โœ… Successfully converted documentation for $TARGET"
              TARGET_ARCHIVES["$TARGET"]="$ARCHIVE_PATH"
          done

      - name: Merge documentation archives
        run: |
          readarray -d '' DOCC_ARCHIVES < <(find "${ARCHIVES_DIR}" -type d -name "*.doccarchive" -print0)
          "${SWIFT_DOCC}" merge "${DOCC_ARCHIVES[@]}" \
              --output-path "${MERGED_DOCC_ARCHIVE}" \
              --synthesized-landing-page-name "App Name iOS"

      - name: Transform for static hosting
        run: |
          xcrun docc process-archive transform-for-static-hosting "${MERGED_DOCC_ARCHIVE}" \
              --hosting-base-path "" \
              --output-path "${STATIC_OUTPUT_DIR}"

      - name: Redirect base url to documentation
        run: |
          echo '<script>window.location.href += "documentation/"</script>' > "${STATIC_OUTPUT_DIR}/index.html"

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs

      - id: deployment
        name: Deploy to GitHub Pages
        uses: actions/deploy-pages@v4

1 Like

Hey Seth,

I haven't tried the specifics here, but the only thing that calls out to me is if you need to keep the building of the catalogs separate, merging them later. I think there may be able to collapse the build and merge into a single step. Although since you need iOS specific builds, that might not be an option. I think the only merged step setup there is with swift-docc-plugin (--enable-experimental-combined-documentation).

I'd love to see some concrete numbers on what's taking the most time with these steps - my supposition is that the majority of time is coming from the xcodebuild docbuild commands. Are you willing to share timing for your use case (suitably anonymized, if you prefer)?

You should be able to skip this and use the docc that exists in the toolchain via xcrun docc.

1 Like

At least at the time of originally doing this, the toolchain version didn't support some of the merge flags we're using. Either way, building of Docc is pretty fast so it's the lowest of the bottlenecks. I'll follow up shortly with the brought timing we're seeing.

1 Like

I think the current Xcode version will work now. Itโ€™s also a version built with release mode so it may perform the other operations more quickly.

1 Like

Here's the timing we're seeing for each step if that helps. We have about 100 modules (targets) that get combined into a single site.

1 Like

Thanks! I'll give that a try.

I've only glanced at your build script but there seems to be a large amount of repeated or unnecessary work.

Your "Build with symbol graphs" task isn't just generating symbol graphs. Because you're using the docbuild action that task is building the documentation archives for everything in that "ProjectScheme" (including dependencies and transitive dependencies).

Later in the "Copy symbol graphs" task you are building all the documentation again in order to pass the dependency archives but AFAICT you're still building the targets in the original order, not in dependency order. If that's correct (that you're not building the targets in dependency order), it looks like you're also only passing the dependencies if they've been built already, so you might be missing dependencies even though you have a copy of all the archives from the previous "Build with symbol graphs" task.


Some smaller things;

  • I don't see anything that uses any of the --emit-digest output so that's likely just (a nontrivial amount of) redundant work.
  • When you build the documentation archives the second time you pass --no-transform-for-static-hosting but later you have an entire docc process-archive transform-for-static-hosting step. This leads to unnecessary IO because you need to read all the files again when you previously had in-memory representations of them.

Also, because of how you're building DocC from source, you're doing all this work with a debug build, without optimizations.

Thanks for the feedback!

Here's an updated script that removes the duplication, but takes the same amount of time unless I'm missing something. It also didn't create the static website despite the "transform-for-static-hosting" flag.

These steps also seem pretty involved in general; not sure how anyone else would know the right steps for getting documentation from many modules into a single static site.

name: Deploy DocC
'on':
  schedule:
    - cron: '0 0,12 * * *'
  workflow_dispatch: null
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: macos-15-xlarge
    env:
      MODULES_DIR: "./Modules"
      DERIVED_DATA: "./tmp/docbuild"
      SYMBOL_GRAPHS_DIR: "./tmp/symbol-graphs"
      ARCHIVES_DIR: "./tmp/doccarchives"
      MERGED_DOCC_ARCHIVE: "./MergedDocs.doccarchive"
      STATIC_OUTPUT_DIR: "./docs"
      PACKAGE_JSON: "./tmp/package.json"
    steps:
      - name: Add Private Repo Auth
        run: git config --global --add url."https://${GITHUB_ACCESS_TOKEN}@github.com/${GITHUB_REPOSITORY_OWNER}".insteadOf "https://github.com/${GITHUB_REPOSITORY_OWNER}"

      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.ref }}
          fetch-depth: 0
          lfs: true

      - name: Setup uv
        uses: astral-sh/setup-uv@v5

      - name: Select Xcode Version
        run: scripts/xcode-version.py --select

      - name: Checkout LFS objects
        run: git lfs checkout

      - name: Prepare signing certificates
        env:
          REDACTED

      - name: Install current Bash on macOS
        run: |
          brew install bash
          echo "Using Bash version: $(bash --version | head -n1)"

      - name: Set up directories for documentation
        run: |
          rm -rf "${ARCHIVES_DIR}" "${MERGED_DOCC_ARCHIVE}" "${STATIC_OUTPUT_DIR}" "${SYMBOL_GRAPHS_DIR}"
          mkdir -p "${ARCHIVES_DIR}" "${STATIC_OUTPUT_DIR}" "${SYMBOL_GRAPHS_DIR}"

      - name: Generate package.json
        run: |
          echo "๐Ÿ“ฆ Generating package.json from Package.swift..."
          (cd "${MODULES_DIR}" && swift package describe --type json) > "${PACKAGE_JSON}"

      - name: Validate package.json
        run: |
          if [ ! -f "${PACKAGE_JSON}" ]; then
              echo "โŒ Error: Failed to generate package.json"
              exit 1
          fi

      - name: Build with symbol graphs
        run: |
          xcodebuild -parallelizeTargets docbuild \
            -project AppName.xcodeproj \
            -scheme AppName \
            -derivedDataPath "${DERIVED_DATA}" \
            -destination 'generic/platform=iOS' \
            ENABLE_SYMBOL_GRAPHS=YES

      - name: Extract and build documentation archives in dependency order
        run: |
          set -e
          shopt -s nullglob globstar

          # Get targets and sort them in dependency order
          TARGETS=$(jq -r '
            .targets[]? | 
            select(.type == "library" or .type == "executable") | 
            .name' "${PACKAGE_JSON}")

          if [[ -z "$TARGETS" ]]; then
              echo "โŒ No targets found in package.json."
              exit 1
          fi

          echo "๐ŸŽฏ Targets found: $TARGETS"

          # Create dependency graph and sort targets topologically
          declare -A TARGET_DEPENDENCIES
          declare -A TARGET_ARCHIVES
          declare -a PROCESSED_TARGETS
          declare -a REMAINING_TARGETS

          # Extract dependencies for each target
          while read -r TARGET; do
              echo "๐Ÿ“š Processing target: $TARGET"
              DEPENDENCIES=$(jq -r --arg TARGET "$TARGET" '
                .targets[]? |
                select(.name == $TARGET) |
                .target_dependencies?[]?' "$PACKAGE_JSON")

              # Handle null case for dependencies
              if [[ -n "$DEPENDENCIES" ]]; then
                  TARGET_DEPENDENCIES["$TARGET"]="$DEPENDENCIES"
              else
                  echo "โš ๏ธ No dependencies found for target: $TARGET"
                  TARGET_DEPENDENCIES["$TARGET"]=""
              fi
              REMAINING_TARGETS+=("$TARGET")
          done <<< "$TARGETS"

          # Simple topological sort - process targets with no unprocessed dependencies first
          while [[ ${#REMAINING_TARGETS[@]} -gt 0 ]]; do
              PROGRESS_MADE=false
              NEW_REMAINING=()
              
              for TARGET in "${REMAINING_TARGETS[@]}"; do
                  CAN_PROCESS=true
                  for DEP in ${TARGET_DEPENDENCIES["$TARGET"]}; do
                      if [[ ! " ${PROCESSED_TARGETS[*]} " =~ " ${DEP} " ]] && [[ " ${REMAINING_TARGETS[*]} " =~ " ${DEP} " ]]; then
                          CAN_PROCESS=false
                          break
                      fi
                  done
                  
                  if [[ "$CAN_PROCESS" == true ]]; then
                      echo "๐Ÿ”จ Processing target: $TARGET (dependencies satisfied)"
                      
                      # Copy symbol graphs for this target
                      TARGET_SYMBOL_GRAPHS_DIR="${SYMBOL_GRAPHS_DIR}/${TARGET}"
                      mkdir -p "$TARGET_SYMBOL_GRAPHS_DIR"
                      XCODE_SYMBOL_GRAPH_DIR_IOS="${DERIVED_DATA}/Build/Intermediates.noindex/AppNameModules.build/Debug-iphoneos/${TARGET}.build/symbol-graph"
                      if [ -d "$XCODE_SYMBOL_GRAPH_DIR_IOS" ]; then
                          cp -R "${XCODE_SYMBOL_GRAPH_DIR_IOS}"
                      fi

                      # Find documentation catalog
                      DOCC_CATALOG=""
                      while IFS= read -r -d '' docc_dir; do
                          DOCC_CATALOG="$docc_dir"
                          echo "๐Ÿ“š Found documentation catalog: $DOCC_CATALOG"
                          break
                      done < <(find "${MODULES_DIR}/Sources/${TARGET}" -type d -name "*.docc" -print0)

                      # Skip if no docc catalog AND no symbol graphs
                      if [[ -z "$DOCC_CATALOG" ]] && [[ -z "$(ls -A "$TARGET_SYMBOL_GRAPHS_DIR")" ]]; then
                          echo "โš ๏ธ Skipping $TARGET - No documentation catalog or symbol graphs."
                          PROCESSED_TARGETS+=("$TARGET")
                          PROGRESS_MADE=true
                          continue
                      fi

                      # Build dependency flags from already processed targets
                      DEPENDENCY_FLAGS=()
                      for DEP in ${TARGET_DEPENDENCIES["$TARGET"]}; do
                          if [[ -n "${TARGET_ARCHIVES[$DEP]}" ]]; then
                              echo "๐Ÿ”— Adding dependency on ${TARGET_ARCHIVES[$DEP]}"
                              DEPENDENCY_FLAGS+=(--dependency "${TARGET_ARCHIVES[$DEP]}")
                          fi
                      done

                      ARCHIVE_PATH="${ARCHIVES_DIR}/${TARGET}.doccarchive"
                      
                      # Add symbol graphs to convert command if they exist
                      SYMBOL_GRAPH_FLAGS=()
                      if [[ -n "$(ls -A "$TARGET_SYMBOL_GRAPHS_DIR")" ]]; then
                          SYMBOL_GRAPH_FLAGS+=(--additional-symbol-graph-dir "$TARGET_SYMBOL_GRAPHS_DIR")
                      fi

                      # Build docc convert command
                      CONVERT_ARGS=()
                      if [[ -n "$DOCC_CATALOG" ]]; then
                          CONVERT_ARGS+=("$DOCC_CATALOG")
                      fi
                      
                      CONVERT_ARGS+=(
                          --fallback-display-name "$TARGET"
                          --fallback-bundle-identifier "com.example.${TARGET}"
                          --fallback-bundle-version "1.0.0"
                          --output-path "$ARCHIVE_PATH"
                          "${DEPENDENCY_FLAGS[@]}"
                          "${SYMBOL_GRAPH_FLAGS[@]}"
                          --enable-experimental-external-link-support
                          --enable-experimental-overloaded-symbol-presentation
                          --hosting-base-path "$TARGET"
                          --transform-for-static-hosting
                      )

                      echo "Running command: xcrun docc convert ${CONVERT_ARGS[*]}"

                      if ! xcrun docc convert "${CONVERT_ARGS[@]}" 2>docc_error_${TARGET}.log; then
                          echo "โŒ Failed to convert documentation for $TARGET"
                          echo "Error output:"
                          cat docc_error_${TARGET}.log
                          echo "โš ๏ธ Skipping $TARGET due to conversion failure."
                      else
                          echo "โœ… Successfully converted documentation for $TARGET"
                          TARGET_ARCHIVES["$TARGET"]="$ARCHIVE_PATH"
                      fi

                      PROCESSED_TARGETS+=("$TARGET")
                      PROGRESS_MADE=true
                  else
                      NEW_REMAINING+=("$TARGET")
                  fi
              done
              
              REMAINING_TARGETS=("${NEW_REMAINING[@]}")
              
              if [[ "$PROGRESS_MADE" == false ]] && [[ ${#REMAINING_TARGETS[@]} -gt 0 ]]; then
                  echo "โŒ Circular dependency detected or missing dependencies. Remaining targets:"
                  printf '%s\n' "${REMAINING_TARGETS[@]}"
                  break
              fi
          done

          echo "โœ… Processed targets in dependency order: ${PROCESSED_TARGETS[*]}"

      - name: Cleanup Derived Data and Symbol Graphs
        if: always()
        run: |
          echo "๐Ÿงน Cleaning up DerivedData and Symbol Graphs..."
          rm -rf "${DERIVED_DATA}" "${SYMBOL_GRAPHS_DIR}"

      - name: Merge documentation archives
        run: |
          readarray -d '' DOCC_ARCHIVES < <(find "${ARCHIVES_DIR}" -type d -name "*.doccarchive" -print0)
          if [[ ${#DOCC_ARCHIVES[@]} -eq 0 ]]; then
              echo "โŒ No documentation archives found to merge"
              exit 1
          fi
          
          echo "๐Ÿ“š Merging ${#DOCC_ARCHIVES[@]} documentation archive(s)..."
          xcrun docc merge "${DOCC_ARCHIVES[@]}" \
              --output-path "${MERGED_DOCC_ARCHIVE}" \
              --synthesized-landing-page-name "AppName iOS"

      - name: Copy merged archive for static hosting
        run: |
          # Since individual archives were already transformed for static hosting,
          # we just need to copy the merged archive to the output directory
          cp -R "${MERGED_DOCC_ARCHIVE}" "${STATIC_OUTPUT_DIR}/documentation"

      - name: Redirect base url to documentation
        run: |
          echo '<script>window.location.href += "documentation/"</script>' > "${STATIC_OUTPUT_DIR}/index.html"

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs

      - id: deployment
        name: Deploy to GitHub Pages
        uses: actions/deploy-pages@v4

      - name: Final Cleanup
        if: always()
        run: |
          echo "๐Ÿงน Final cleanup of archives and temp files..."
          rm -rf "${ARCHIVES_DIR}" "${MERGED_DOCC_ARCHIVE}" "${PACKAGE_JSON}"

The updated script hasn't really removed any duplicated work, so it's not surprising that it still takes the same amount of time.

The "Build with symbol graphs" task still performs the docbuild action instead of the (default) build action which means that it's still s building the documentation archives for everything in the scheme (including dependencies and transitive dependencies):

- name: Build with symbol graphs
  run: |
    xcodebuild -parallelizeTargets docbuild \
    ...

Individual developers aren't meant to perform these steps manually like this. The idea is that the tools would do it for them. For Swift packages building their documentation using the Swift-DocC Plugin, this is already the case. If you pass the --enable-experimental-combined-documentation to swift package generate-documentation, the plugin:

  • schedules symbol graph generation and documentation builds for targets in dependency order, running independent tasks concurrently where possible
  • passes dependency archives between target's documentation builds
  • merges the built documentation archives into a single combined output and writes it to the specified --output-path (or the default output location).

However, if you can't build your Swift package with swift build then you also can't use swift package generate-documentation to build documentation for it. Instead, you end up needing to perform these steps manually to achieve the same output because the tools you need to use to build your project doesn't support doing that work you yet.

1 Like

Right. The main issue is that we're not trying to build a Swift Package documentation, as this is for our iOS app. We're aiming to create internal documentation. So, we don't have a clear step-by-step on the right script/order of build steps for non-swift packages. We've had to piece together suggestions from various places leading to our most recent one that works, but isn't clear if it's the best solution.

1 Like