Clangler

0.1.0

A Swift package for parsing Clang module map files
daltonclaybrook/Clangler

What's New

Sabian

2021-11-06T17:50:15Z

This is the initial beta release of Clangler! If you are using it in your project and find any bugs, or if you have a use-case that's not easily accommodated by the current API, please feel free to open an issue or pull request.

Build Status codecov Platforms License

Clangler is a Swift package used to parse Clang module map files into an abstract syntax tree (AST) representation. Once parsed, you can inspect or manipulate the nodes in the file, then generate and save a new file reflecting your changes.

Examples

Find the names of all modules in a file:

func findAllTopLevelModuleNames(fileURL: URL) throws -> [String] {
    let moduleMap = try Parser().parseFile(at: fileURL).get()
    return moduleMap.moduleDeclarations.map(\.moduleId.rawValue)
}

Remove an existing umbrella header declaration and replace it with an umbrella directory:

func convertToUmbrellaDirectory(fileURL: URL) throws {
    var moduleMap = try Parser().parseFile(at: fileURL).get()

    // Find the module declaration and the existing umbrella header
    guard var declaration = moduleMap.moduleDeclarations.first?.local,
          let umbrellaHeaderMemberIndex = declaration.members
            .firstIndex(where: { $0.header?.kind == .umbrella })
    else { return }

    // Replace the umbrella header with an umbrella directory
    declaration.members[umbrellaHeaderMemberIndex] = .umbrellaDirectory(
        UmbrellaDirectoryDeclaration(filePath: "Headers")
    )

    // Replace the module declaration with the new one
    moduleMap.moduleDeclarations[0] = .local(declaration)

    // Save the modified file
    let generator = Generator(indentationStyle: .spaces(4))
    let newFileContents = generator.generateFileContents(with: moduleMap)
    try newFileContents.write(to: fileURL, atomically: true, encoding: .utf8)
}

Create a brand new module map from scratch instead of parsing one:

func buildModuleMapFromScratch(moduleName: String, headerPaths: [String]) throws {
    let moduleMap = ModuleMapFile(
        moduleDeclarations: [
            .local(LocalModuleDeclaration(
                explicit: false,
                framework: true,
                moduleId: ModuleId(rawValue: moduleName),
                attributes: [],
                members: headerPaths.map { filePath in
                    .header(HeaderDeclaration(
                        kind: .standard(private: false),
                        filePath: filePath,
                        headerAttributes: []
                    ))
                }
            ))
        ]
    )

    // Save the file
    let generator = Generator(indentationStyle: .spaces(4))
    let fileContents = generator.generateFileContents(with: moduleMap)
    let fileURL = URL(fileURLWithPath: "path/to/\(moduleName)/module.modulemap")
    try fileContents.write(to: fileURL, atomically: true, encoding: .utf8)
}

Discover syntax errors in a file:

func printAllSyntaxErrors(fileURL: URL) throws {
    let result = try Parser().parseFile(at: fileURL)
    guard case .failure(let syntaxErrors) = result else {
        return print("No syntax errors")
    }

    for error in syntaxErrors {
        print("line: \(error.line), column: \(error.column), description: \(error.description)")
    }
}

Notable types

  • Parser — Used to parse the contents of a Clang module map file into an abstract syntax tree (AST) representation
  • Lexer — Scans a module map string and produces tokens in the module map grammar. You will typically not instantiate this type directly as Parser uses it under the hood.
  • Generator — Used to generate module map file contents from an abstract syntax tree (AST) representation. This is the reverse of Parser.
  • ModuleMapFile — The root node in the module map AST. This represents a complete module map file as a collection of declarations.

Installation

In Xcode, you can add this package to your project by selecting File -> Swift Packages -> Add Package Dependency… Enter the Clangler GitHub URL and follow the prompts.

If you use a Package.swift file instead, add the following line inside of your package dependencies array:

.package(url: "https://github.com/daltonclaybrook/Clangler", from: "0.1.0"),

Now add Clangler as a dependency of any relevant targets:

.target(name: "MyApp", dependencies: ["Clangler"]),

License

Clangler is available under the MIT license. See LICENSE.md for more information.

Description

  • Swift Tools 5.3.0
View More Packages from this Author

Dependencies

  • None
Last updated: Sat Sep 30 2023 17:38:57 GMT-0900 (Hawaii-Aleutian Daylight Time)