5

I've been trying to access a file in my command line tool Xcode project but program isn't able to find the file path. I'm assuming it's because the file isn't being copied to my project.

I've gone to build phases and added my file (graph2.net) but the program can't find the file.

enter image description here

func readGraph() {
    if let path = Bundle.main.path(forResource: "graph2", ofType: "net") {
        print(path)
    } else {
        print("Failed")
    }
}

always returns failed. However in an iOS app, the option to copy bundle resources exists and I am able to find the file. How can I solve this issue?

leedex
  • 963
  • 8
  • 19
  • APIs like `Bundle.main.path(forResource` will work for a commandline app by looking in the same directory the binary executable ends up in. I'm doing this manually for now. Use `Copy Files` instead of `Copy Bundle Resources` – hippietrail Sep 01 '23 at 08:28

2 Answers2

9

A command-line-tool only consists of an executable. No bundle is created and what you are trying to do is not possible.

You’ll have to place the file in some other place and load it from there.

idmean
  • 14,540
  • 9
  • 54
  • 83
  • I made my target using the "Command Line Tool" template, which produces a raw executable like this. Is there a build setting I can change to switch between the output being the "raw binary" vs having it bundled up into an App? Or do I have to delete my target entirely and recreate it from the "App" template? – Alexander Oct 24 '21 at 02:48
  • @Alexander I would add a new target to your project and then add your files to the new target. – idmean Oct 24 '21 at 07:58
  • 1
    Nevermind, turns out it was an XY problem, and I didn't actually want a bundle after all. I was created a Privileged Helper for macOS, which requires the build product to have an Info.plist. I thought this necessitates it being wrapped up into a bundle, but as it turns out, you can [embed plists and other files directly into the Mach-O executable files](https://www.woodys-findings.com/posts/cocoa-implement-privileged-helper#embedthesetupfiles). Crazy! – Alexander Oct 24 '21 at 13:46
0

You can create a bundle and place it in same directory as your executable file.

import Foundation

private class BundleLocator {}

/// Category for easily retrieving the accompanying bundle.
extension Bundle {
  /// Local bundle, assuming it resides in the main bundle.
  static var resources: Bundle {
    let executableBundle = Bundle(for: BundleLocator.self)
    guard let bundlePath = executableBundle.path(forResource: "Resources", ofType: "bundle") else {
      fatalError(
        "Could not find Resources bundle. Make sure you copy the bundle to the same folder as the executable file."
      )
    }

    guard let bundle = Bundle(path: bundlePath) else {
      fatalError("Failed to create bundle from path: \(bundlePath)")
    }

    return bundle
  }
}
Yoav
  • 5,962
  • 5
  • 39
  • 61