Undefined symbols for architecture x86_64 for executable

The last couple of days I've been getting undefined symbol errors.
I'm creating a package that's an executable. I created it through the cli

swift package init --type executable

It's a Vapor console application. I've got the following structure:

- Sources
    - Vii
    - ViiLibrary
- Tests
    - ViiTests
        - ViiTests.swift

I'm basically using my ViiLibrary as a target that can be tested as according to this answer you can't test an executable.

Inside my Vii directory I am importing the ViiLibrary but when I try to access anything in that Library I get symbol errors.

Undefined symbols for architecture x86_64:
  "ViiLibrary.ViiDatabaseType.init(input: Swift.String) -> ViiLibrary.ViiDatabaseType", referenced from:
      Vii.ViiCommand.run(using: ConsoleKit.CommandContext, signature: Vii.ViiCommand.Signature) throws -> () in Vii.o
  "ViiLibrary.Credentials.init(port: Swift.Int, host: Swift.String, username: Swift.String, password: Swift.String, database: Swift.String) -> ViiLibrary.Credentials", referenced from:
      Vii.ViiCommand.run(using: ConsoleKit.CommandContext, signature: Vii.ViiCommand.Signature) throws -> () in Vii.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

And I really don't know why or how to fix these? I am importing the same ViiLibrary into my Tests via @testable import ViiLibrary and they are able to run fine when being tested. But not if they are inside my Vii target.

I've cleaned the build, wiped the derived data and restarted XCode a few times, but it doesn't seem to resolve the problem.

For completeness, here is the Credentials struct. I have declared all the types, properties and initializes on both library types as public

public struct Credentials {
    public let port: Int
    public let host: String
    public let username: String
    public let password: String
    public let database: String
    
    public init(port: Int, host: String, username: String, password: String, database: String){
        self.port = port
        self.host = host
        self.username = username
        self.password = password
        self.database = database
    }
}

Are the relevant symbols public? They need to be if you want to access them from a separate module. (@testable cheats in that respect, but it isn’t reliable outside of test targets.)

Yes I should have mentioned they are. Credentials for example is a public struct with public vars and a public initializer. I will post when back at my mac.

public struct Credentials {
    public let port: Int
    public let host: String
    public let username: String
    public let password: String
    public let database: String
    
    public init(port: Int, host: String, username: String, password: String, database: String){
        self.port = port
        self.host = host
        self.username = username
        self.password = password
        self.database = database
    }
}

Well I thought I had found your repository here, but its master builds just fine and does not seem to contain either the offending symbols or your pasted code. Nor does it have any other branches. Maybe if you pushed whatever you have locally to a branch I could be more of a help.

Yes that's it. I just updated it. I have actions enabled and it failed on Xenial and Bionic, as you can see here. Although only for one of the types

ViiTests declares a dependency ViiLibrary; Vii doesn’t. That is why only one of them is importing it successfully.

1 Like

Thank you!! I thought I checked this. XCodes error could have been a bit friendlier here though

Because neither target depended on the other, they were being built at once, and that meant part of one was available when the other tried to link it. Exactly how much was available differed with each attempt and that was why the messages were so unpredictable. Had you tried building only one target, the error would have been clearer, because there would have been nothing to import at all, so it would have failed immediately:

swift package clean
swift build --target Vii

It would certainly be nice if packages could validate that imports are declared as dependencies in order to immediately detect the root of the problem instead of just reporting the symptom. Unfortunately since many modules come from outside the package anyway—Foundation or Glibc for example—I’m not sure such a check would be feasible.

1 Like

Facing similar issue while building ObjC static libraries.

- Sources
    - VPNKit
    - VPNKitAdapter (depends on VPNKit)

Here is Package file

let package = Package(
    name: "VPNKit",
    platforms: [
        .iOS(.v14),
        .macOS(.v10_15)
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "VPNKit",
            type:.static,
            targets: ["VPNKit"]),
        .library(
            name: "VPNKitAdapter",
            type:.static,
            targets: ["VPNKitAdapter"])
     ],
     dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", from: "3.8.0")
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "VPNKit",
            dependencies: [
                .product(name: "CocoaLumberjack", package: "CocoaLumberjack"),
                .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack")
            ],
            path: "Sources/VPNKit",
            exclude: [
                "Info.plist",
                "../../fastlane",
                "../../.gitmodules",
                "../../DemoProject",
                "../../Cartfile",
                "../../Gemfile",
                "../../.gitlab-ci.yml",
                "SwiftSources"
            ],
            cSettings: {
                var settings: [CSetting] = [
                        .define("GCC_PREFIX_HEADER", to: "PrefixHeader.pch", nil)
                    ]
                settings.append(contentsOf: projectVPNKitcHeaderSearchPaths)
                
                return settings
            }(),
            linkerSettings: [
                .linkedFramework("Foundation"),
                .linkedFramework("Security"),
                .linkedFramework("CoreData"),
                .linkedFramework("SystemConfiguration", .when(platforms: [.iOS, .macOS])),
                .linkedFramework("ServiceManagement", .when(platforms: [.macOS])),
                .linkedFramework("Cocoa", .when(platforms: [.macOS]))
            ]),
        .testTarget(
            name: "VPNKitTests",
            dependencies: ["VPNKit"],
            path: "Tests/VPNKitTests"
        ),
        .target(
            name: "VPNKitAdapter",
            dependencies: [
                .target(name: "VPNKit")
            ],
            path: "Sources/VPNKitAdapter",
            exclude: [
                "Info.plist",
                "../../fastlane",
                "../../.gitmodules",
                "../../DemoProject",
                "../../Cartfile",
                "../../Gemfile",
                "../../.gitlab-ci.yml",
                "SwiftSources"
            ],
            sources: [
                "Models"
            ],
            resources: [
                .copy("Resources/VPNCommon.xcdatamodeld"),
                .copy("Resources/Version5to6.xcmappingmodel")
            ],
            cSettings: {
                var settings: [CSetting] = [
                        .define("GCC_PREFIX_HEADER", to: "VPNKitAdapter_PrefixHeader.pch", nil)
                    ]
                settings.append(contentsOf: projectVPNKitAdaptercHeaderSearchPaths)
                
                return settings
            }(),
            linkerSettings: [
                .linkedFramework("Foundation"),
                .linkedFramework("Security"),
                .linkedFramework("SystemConfiguration", .when(platforms: [.iOS, .macOS])),
                .linkedFramework("ServiceManagement", .when(platforms: [.macOS])),
                .linkedFramework("Cocoa", .when(platforms: [.macOS])),
                .linkedFramework("CoreData", .when(platforms: [.iOS, .macOS]))
            ]),
        .testTarget(
            name: "VPNKitAdapterTests",
            dependencies: ["VPNKitAdapter"],
            path: "Tests/VPNKitAdapterTests"
        )
      ]
)

Below issue Im facing, Added local package at VPNKitPackageTest Xcode sample project
and testing both libraries API at VPNKitTestingAPIs.swift class.

V3APIAdapter.h is public class from VPNKitAdapter library which has @import VPNKit; statement.

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_V3APIAdapter", referenced from:
      objc-class-ref in VPNKitTestingAPIs.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Please help me to resolve it