Integrating C++ system library

I'm having trouble trying to integrate Gosu in my Swift project. Adding SDL2 (with module.modulemap) was easy and works no problem. Bear in mind that I'm a complete noob to Swift.

I wanted to jump some hoops and add Gosu directly as it implements some of the functionality to create games easier compared to plain SDL2.

I have Gosu installed through Homebrew.

My Sources/CGosu/module.modulemap:

module CGosu [system] {
  umbrella header "/opt/homebrew/include/Gosu/Gosu.hpp"
  export *
}

My Package.swift:

// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
  name: "SwiftGosu",
  platforms: [
    .macOS(.v14)
  ],
  targets: [
    .executableTarget(
      name: "SwiftGosu",
      dependencies: ["CGosu"],
      path: "Sources"
    ),
    .systemLibrary(
      name: "CGosu",
      providers: [.brew(["libgosu"])]
    ),
  ]
)

Output for swift run:

error: emit-module command failed with exit code 1 (use -v to see invocation)
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/opt/homebrew/include/Gosu/Gosu.hpp"
        ^
/opt/homebrew/include/Gosu/Gosu.hpp:9:10: note: in file included from /opt/homebrew/include/Gosu/Gosu.hpp:9:
#include <Gosu/Audio.hpp>
         ^
/opt/homebrew/include/Gosu/Audio.hpp:3:10: note: in file included from /opt/homebrew/include/Gosu/Audio.hpp:3:
#include <Gosu/Fwd.hpp>
         ^
/opt/homebrew/include/Gosu/Fwd.hpp:3:1: error: unknown type name 'namespace'
namespace Gosu
^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/opt/homebrew/include/Gosu/Gosu.hpp"
        ^
/opt/homebrew/include/Gosu/Gosu.hpp:9:10: note: in file included from /opt/homebrew/include/Gosu/Gosu.hpp:9:
#include <Gosu/Audio.hpp>
         ^
/opt/homebrew/include/Gosu/Audio.hpp:3:10: note: in file included from /opt/homebrew/include/Gosu/Audio.hpp:3:
#include <Gosu/Fwd.hpp>
         ^
/opt/homebrew/include/Gosu/Fwd.hpp:3:15: error: expected ';' after top level declarator
namespace Gosu
              ^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/opt/homebrew/include/Gosu/Gosu.hpp"
        ^
/opt/homebrew/include/Gosu/Gosu.hpp:9:10: note: in file included from /opt/homebrew/include/Gosu/Gosu.hpp:9:
#include <Gosu/Audio.hpp>
         ^
/opt/homebrew/include/Gosu/Audio.hpp:4:10: note: in file included from /opt/homebrew/include/Gosu/Audio.hpp:4:
#include <Gosu/IO.hpp>
         ^
/opt/homebrew/include/Gosu/IO.hpp:4:10: error: 'algorithm' file not found
#include <algorithm>
         ^
/Users/piotr/Work/GitHub/SwiftGosu/Sources/main.swift:4:8: error: could not build Objective-C module 'CGosu'
import CGosu
       ^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/opt/homebrew/include/Gosu/Gosu.hpp"
        ^
/opt/homebrew/include/Gosu/Gosu.hpp:9:10: note: in file included from /opt/homebrew/include/Gosu/Gosu.hpp:9:
#include <Gosu/Audio.hpp>
         ^
/opt/homebrew/include/Gosu/Audio.hpp:3:10: note: in file included from /opt/homebrew/include/Gosu/Audio.hpp:3:
#include <Gosu/Fwd.hpp>
         ^
/opt/homebrew/include/Gosu/Fwd.hpp:3:1: error: unknown type name 'namespace'
namespace Gosu
^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/opt/homebrew/include/Gosu/Gosu.hpp"
        ^
/opt/homebrew/include/Gosu/Gosu.hpp:9:10: note: in file included from /opt/homebrew/include/Gosu/Gosu.hpp:9:
#include <Gosu/Audio.hpp>
         ^
/opt/homebrew/include/Gosu/Audio.hpp:3:10: note: in file included from /opt/homebrew/include/Gosu/Audio.hpp:3:
#include <Gosu/Fwd.hpp>
         ^
/opt/homebrew/include/Gosu/Fwd.hpp:3:15: error: expected ';' after top level declarator
namespace Gosu
              ^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/opt/homebrew/include/Gosu/Gosu.hpp"
        ^
/opt/homebrew/include/Gosu/Gosu.hpp:9:10: note: in file included from /opt/homebrew/include/Gosu/Gosu.hpp:9:
#include <Gosu/Audio.hpp>
         ^
/opt/homebrew/include/Gosu/Audio.hpp:4:10: note: in file included from /opt/homebrew/include/Gosu/Audio.hpp:4:
#include <Gosu/IO.hpp>
         ^
/opt/homebrew/include/Gosu/IO.hpp:4:10: error: 'algorithm' file not found
#include <algorithm>
         ^
/Users/piotr/Work/GitHub/SwiftGosu/Sources/main.swift:4:8: error: could not build Objective-C module 'CGosu'
import CGosu
       ^
error: fatalError

How should I go ahead and add it? Should I clone the Gosu repository directly to Sources/CGosu and use that instead? With the systemLibrary definition it seems I can't make it treat it as a C++ library.

Hey, it looks like you need to enable CXX Interoperability mode in the project. See here: Swift.org - Setting Up Mixed-Language Swift and C++ Projects

By the looks of your Packge.swift, you’re importing Gosu as a C module which is why it’s whining about it. Have a look at the guide and see if you can enable CXX interop for the project.

1 Like

…and per Modules — Clang 19.0.0git documentation, you can put requires cplusplus in your module definition to make sure this doesn't happen by accident.

1 Like

Ok, this is now better. I also had to figure out that the main executable target had to link to the library, too so that it could find the symbols.

2 Likes

Thank you for the help @xtremekforever and @jrose!

1 Like

Glad you could get it working!!

@xtremekforever BTW. Do you know if it's possible to directly use namespaced C++ classes? Or do I need a C wrapper for those?

I think it should be. In my case I was using namespaced classes from our proprietary library where all classes were under a “lib” namespace, and I did stuff like:

let myInstance = lib.MyClass()

I did have issues creating instances of classes that used fancy types like std::atomic and std::mutex- it seemed that having members using those type classes caused Swift to not even show the class, so they had to be wrapped in C functions to get instances instead.

Are you having issues seeing your namespaced classes?

1 Like

Cool, I think I finally got it to work! Next step, inheritance (or wrapping?).

I've got this C++ class thing. In order to use it, I need to inherit from it, and override the update method.

Here's an example in C++.

@xtremekforever Would you know how could this be achieved in Swift? Directly trying to inherit does not work.

/Users/piotr/Work/GitHub/SwiftGosu/Sources/main.swift:6:24: error: 'Window' is not a member type of enum '__ObjC.Gosu'
class GameWindow: Gosu.Window {
                  ~~~~ ^
/opt/homebrew/include/Gosu/Window.hpp:23:11: note: record 'Window' is not automatically available: does not have a copy constructor or destructor; does this type have reference semantics?
    class Window : private Noncopyable
          ^
          SWIFT_SHARED_REFERENCE(<#retain#>, <#release#>)

Obviously, as you can tell, I'm new to C++/Swift, so I have no idea what I'm doing :P.

When it comes to this I'm not sure if it's really possible in Swift right now. You may just need to make a class in C++ that inherits from it and provides an update method, and that maybe calls a Swift class method instead.

1 Like