Skip to content

Instantly share code, notes, and snippets.

@Kacarott
Created September 1, 2020 05:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kacarott/71f2c9f7b192c22e7bfcfcedf357b0eb to your computer and use it in GitHub Desktop.
Save Kacarott/71f2c9f7b192c22e7bfcfcedf357b0eb to your computer and use it in GitHub Desktop.
Using SFML in Atom [Mac]

SFML and Atom (Mac)

Here is a small guide for how to make Atom cooperate with SFML.

I am writing this because while I could find very limited information on making the combination work, it was never for a Mac environment. And so after some experimenting I found a solution that seems to work.

Atom is NOT an IDE

First off, Atom is just a text editor. It never claims to be more. But the beauty of Atom is in the range of plugins available, making it easy to build it into an IDE if you wish. Introducing:

Script

Script is a wonderful package for Atom that adds compilers for a huge number of languages. You can check out the GitHub page for more info.

We will be using Script as our compiler interface to make SFML work within Atom. Similar techniques are probably possible with other C++ compiler packages, but I don't have any experience with those.

Install

  1. Download Script with apm install script or directly from inside Atom. See their page for more.
  2. Script compiles C++ with xcrun and clang++. Make sure you have these, or install them.
  3. Download SFML for MacOS from here. Go ahead and decompress the file.
  4. Navigate to /usr/local/Frameworks/ (You can see hidden files and folders with command shift . )
  5. From inside the decompressed SFML folder, copy everything from extlibs and Frameworks into /usr/local/Frameworks/. ~Note: I'm not 100% sure whether the extra libraries are working this way. Let me know if they don't.
  6. Everything from /SFML-x.x.x/include/ needs to go in /usr/local/include/
  7. And finally everything from /SFML-x.x.x/lib/ goes into /usr/local/lib/

You don't need any of the other files, but some (especially Templates) might be useful as references later.

Modifying Script

While Script comes with an assortment of run options, I couldn't find a way use them to compile and open my SFML project in one command.

Potentially someone smarter could work out how to use the run options more effectively, however my solution just edits the Script source files to automatically read my main.cpp, and include the SFML object files if it finds any of the SFML headers.

I also added a code snippet to have it save the compiled app to my project directory, rather than a temp file. However that is just my own preference.

At the moment SFML headers have to be included in main.cpp or not at all. Using the run options of Script may also not work. I might try solve these at later date but I'm happy for now.

Anyway, on to the code:

  1. The file we are interested in is:

/Users/You/.atom/packages/script/lib/grammars/c.coffee

  1. First we add the main command arguments as one variable. Paste the following somewhere near the top of the file (I put it straight under 'options'):
#path = require 'path'
#{OperatingSystem, command} = GrammarUtils = require '../grammar-utils'

#os = OperatingSystem.platform()
#windows = OperatingSystem.isWindows()

#options = '-Wall -include stdio.h'
sfmloptions = ' -framework sfml-graphics -framework sfml-audio -framework sfml-network -framework sfml-system -framework sfml-window -F /usr/local/Frameworks'
  1. Next, we are only interested in the 'C++' section of the code. We will edit both selection based and file based commands, so that we can use both. Edit the code (around line 80) to look like the following: (I have commented out unchanged lines).
# exports['C++'] =
#   'Selection Based':
#     command: 'bash'
#     args: (context) ->
#       code = context.getCode()
      if code.indexOf("#include <SFML/Graphics.hpp>") != -1 || code.indexOf("#include <SFML/Audio.hpp>") != -1 || code.indexOf("#include <SFML/Network.hpp>") != -1 || code.indexOf("#include <SFML/System.hpp>") != -1 || code.indexOf("#include <SFML/Window.hpp>") != -1
        options += sfmloptions
#      tmpFile = GrammarUtils.createTempFileWithCode(code, '.cpp')
#      args = switch os
#        when 'darwin'
#          "xcrun clang++ -std=c++14 #{options} -fcolor-diagnostics -include iostream #{tmpFile} -o /tmp/cpp.out && /tmp/cpp.out"
#        when 'linux'
#          "g++ #{options} -std=c++14 -include iostream #{tmpFile} -o /tmp/cpp.out && /tmp/cpp.out"
#      return ['-c', args]

#  'File Based': {
#    command
#    args: ({filepath}) ->
      fs = require 'fs'
      getCodeFromFile = ->
        fs.readFileSync filepath, 'utf8'
      code = getCodeFromFile()
      if code.indexOf("#include <SFML/Graphics.hpp>") != -1 || code.indexOf("#include <SFML/Audio.hpp>") != -1 || code.indexOf("#include <SFML/Network.hpp>") != -1 || code.indexOf("#include <SFML/System.hpp>") != -1 || code.indexOf("#include <SFML/Window.hpp>") != -1
        options += sfmloptions
#      args = switch os
#        when 'darwin'
#          "xcrun clang++ -std=c++14 #{options} -fcolor-diagnostics -include iostream '#{filepath}' -o /tmp/cpp.out && /tmp/cpp.out"
#        when 'linux'
#          "g++ -std=c++14 #{options} -include iostream '#{filepath}' -o /tmp/cpp.out && /tmp/cpp.out"
#        when 'win32'
#          if GrammarUtils.OperatingSystem.release().split('.').slice -1 >= '14399'
#            filepath = path.posix.join.apply(path.posix, [].concat([filepath.split(path.win32.sep)[0].toLowerCase()], filepath.split(path.win32.sep).slice(1))).replace(':', '')
#            "g++ -std=c++14 #{options} -include iostream /mnt/#{filepath} -o /tmp/cpp.out && /tmp/cpp.out"
#      return GrammarUtils.formatArgs(args)
#  }

And that should do it! Your SFML code should now be running, or almost. The following code bits are for quality of life mostly.

Replacing resourcePath()

If you first try to run the example program that SFML provides in the templates folder, you will find that the function resourcePath() raises an error (undefined).

This is purely a helper function, and it's possible to write programs simply by providing the full path to your resources. If you still need it however, we can write our own small function using the library <filesystem> introduced in C++17.

  1. First make sure that your clang version is at least version 5

clang --version

  1. Edit c.coffee again, to switch to c++17 (the default is c++14) Edit both file mode and selection mode:
#       args = switch os
#         when 'darwin'
          "xcrun clang++ -std=c++17 #{options} -fcolor-diagnostics -include iostream #{tmpFile} -o /tmp/cpp.out && /tmp/cpp.out"
#        when 'linux'
#          "g++ #{options} -std=c++14 -include iostream #{tmpFile} -o /tmp/cpp.out && /tmp/cpp.out"
  1. Now we can define resourcePath() wherever we need it.
#include <filesystem>

std::string resourcePath() {
  return std::string(std::filesystem::current_path()) + "/";
}

Changing Build Location

If, like me, you rather have your compiled app right in your working directory rather than in a temp folder, change the following (again in c.coffee). Note, my version will only change if I am working on an SFML project, and only in file mode. You can edit as you wish.

#if code.indexOf("#include <SFML/Graphics.hpp>") != -1 || code.indexOf("#include <SFML/Audio.hpp>") != -1 || code.indexOf("#include <SFML/Network.hpp>") != -1 || code.indexOf("#include <SFML/System.hpp>") != -1 || code.indexOf("#include <SFML/Window.hpp>") != -1
#  options += sfmloptions
   dir = '/path/to/directory/myapp.app'
#args = switch os
#   when 'darwin'
     "xcrun clang++ -std=c++17 #{options} -fcolor-diagnostics -include iostream '#{filepath}' -o #{dir} && #{dir}"
#  when 'linux'

Fixing Linter Issues

Finally, while your code may be running smoothly now, there is a chance that your linter may be greatly disagreeing with all these changes. I use linter-gcc but similar steps probably work for other linters.

  1. In linter-gcc settings add -std=c++17 to your C++ Flags.

  2. Linters using a homebrew installation of gcc won't be able to see the SFML header files. I found the easiest fix was to copy the SFML header folder inside to:

/usr/local/Cellar/gcc/x.x.x/include/c++/x.x.x/

  • You could probably also just pass the header directory to gcc as an argument but I couldn't get that to work for some reason.

And that's it!

If you have other questions or issues or i forgot something or made a mistake somewhere, just let me know. This is my first 'guide' so there's bound to be errors. Anyway happy coding!

- Keldan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment