Sublime Forum

Compile with dynamic libs / g++ and SFML (linux)

#1

Hi :slightly_smiling:

I’m trying to compile some C++/SFML code, but I’m having some troubles.

I have created a small main.cpp program on my desktop, it works fine when I write, from my terminal :
g++ -c main.cpp -I/Volumes/DATA/SFML/include
g++ main.o -o sfml -L/Volumes/DATA/SFML/lib -lsfml-graphics -lsfml-window -lsfml-system
export LD_LIBRARY_PATH=/Volumes/DATA/SFML/lib && ./sfml

So I tried to create a new build systems, where I wrote :
“cmd” : [“g++”, “-c”, “${file}”, “-I/Volumes/DATA/SFML/include”],
“cmd” : [“g++”, “${file_path}/${file_base_name}.o”, “-o”, “sfml-app”, “-L/Volumes/DATA/SFML/lib”, “-lsfml-graphics”, “-lsfml-window”, “-lsfml-system”],
“cmd” : [“export LD_LIBRARY_PATH=/Volumes/DATA/SFML/lib && ./sfml-app”]

But it didnt work. Seems that the sfml-app isnt created.

Does anyone have a solution for this ?

Thanks :slightly_smiling:

0 Likes

#2

Build systems can’t have more than one command in them (so far as I am aware, anyway), so doing things this way would require a few build systems, which would be a pain in the butt as you have to switch and trigger each one.

A better way to do this would be to use a tool that’s made specifically for this purpose. There are many such tools, but the one that I use most often is make, so I’ll show you how to do this with that one. If your Linux box has gcc installed, then it should have make as well.

Warning: Long post ahead; get a pillow ready in case you fall asleep

As a simple synopsis, make is a system for creating software by specifying rules that show what files depend on other files and what commands bring everything up to date. Below is a simple example based on what you posted above. I’ll go over what the file is doing for you, but I would recommend a tutorial or more reading on Make if you decide to use it (for example this one, which was the first hit in google when I checked).

NOTE: Make is very particular about using tabs instead of spaces to indent things; the indented lines in the below file have to be tabs or make will yak on you. When you edit a Makefile in Sublime, sublime takes care of making sure that tabs are used for indenting. You may need to modify the file if you just copy/paste this example, though.

Sample Makefile


# The location where SFML is installed
SFML_DIR=/Volumes/DATA/SFML

# Location where SFML libraries are located
LIBDIR=$(SFML_DIR)/lib

# Arguments to pass to the compiler
CFLAGS=-I$(SFML_DIR)/include

# SFML (and other) libraries that need to be linked with
LIBS=-lsfml-graphics -lsfml-window -lsfml-system

# Set the rule that links the executable as the default
# This is the default because it is *first* in the file,
# not because of it's name!
default: sfml

# Create the executable file
sfml: main.o
	g++ -o sfml -L$(LIBDIR) $(LIBS) main.o

# Compile the source file
main.o: main.cpp
	g++ -c main.cpp $(CFLAGS) -o main.o

# For running
run: sfml
	LD_LIBRARY_PATH=$(LIBDIR) sfml

You would save this in a file named Makefile in the same directory as the one that contains your source file. Sublime knows about building via Make, so you should just need to press Ctrl+B in order to build everything, although you may need to set the build system back to Automatic or Make from the Tools > Build System menu if you’ve been using a custom build system. Since Make is a supported build system out of the box, you can double click on any compiler errors in the build output and sublime will jump to the appropriate location for you.

The first few lines of the Makefile set up simple variables that are later expanded in the rules; this isn’t really necessary but I find it makes the rest of the file easier to read; plus it makes changes easier. For example, if you change where SFML is installed, you only have to fix one thing and everything else will Just Work™.

The rest of the file consists of various make rules or targets that specify what to do. The general format is:

target: dependencies
    shell commands to create/update target

The idea is that each rule specifies something that needs to be made (the target), what things are needed to make it (the dependencies) and what commands are used to do that. Using these rules, make will deduce what order to perform the steps in (e.g. it tries to compile the source files to an object file before it tries to link the object file into an executable).

So, reading from the top down in the sample file:

  1. By default (i.e. when you just type make and nothing more), try to bring sfml up to date
    • since there is no file named default, this rule will always trigger, and so make will always try to bring sfml up to date
    • what makes this rule the default rule is not it’s name, but that it is the first rule in the file
  2. The output file sfml requires a file named main.o; once main.o exists, execute the following shell commands to make sfml
    • if main.o does not exist, make will first go find the rule that tells it how to build that file before it will execute this rule
  3. The output file main.o depends on a file named main.cpp; once main.cpp exists, execute the following shell commands to make main.o
    • The assumption here is that main.cpp always exists. So really, this rule is saying "any time main.cpp changes, you need to rebuild main.o, which will in turn cause sfml to be recreated.

The last rule (run) is not really needed in the general case. You can probably tell from it’s name and the shell command that is part of the rule that the idea is that it runs the actual program. From the command line, you would enter the command make run, which tells make that it should try to bring the run target up to date, which it will try to do by actually running the executable.

Bonus marks

Although Sublime has support for Make built in, there’s no direct built in way to run your program from sublime after you’ve built it. You can drop to a terminal and run it from there, or you could create a specific key binding that would run your executable for you.

You might also recognize that if you put the run rule as the first rule in the Makefile, it would become the default rule, and so when you build it will automatically compile everything for you and then run the result. That’s certainly a thing you can do, but it takes away your ability to build the binary without running it.

What I tend to do is take advantage of how the Makefile has a run target in it that is not the default target. I add the following to my .sublime-project files where I’m working with C/C++ to override the built in Make build system (You could also just override the build system in general so it works everywhere, of course):

    "build_systems" :
    [
        {
            "name": "Make",
            "shell_cmd": "make",
            "file_regex": "^(..[^:\n]*):([0-9]+):?([0-9]+)?:? (.*)$",
            "working_dir": "${folder:${project_path:${file_path}}}",
            "selector": "source.makefile",
            "syntax": "Packages/Makefile/Make Output.sublime-syntax",
            "keyfiles": ["Makefile", "makefile"],

            "variants":
            [
                {
                    "name": "Clean",
                    "shell_cmd": "make clean"
                },

                {
                    "name": "Run",
                    "shell_cmd": "make run"
                }

            ]
        }
    ]

The bulk of this is a direct copy of the built in Make build system which has been enhanced with the variants listed above. Along with this key binding:

    {
        "keys": ["ctrl+alt+shift+r"],
        "command": "build" ,
        "args":
        {
            "variant": "Run"
        }
    }

Pressing Ctrl+Alt+Shift+R will invoke make run for you, which will run the executable. Even better, since the run rule in the Makefile depends on the executable, if your sublime has Tools > Save All On Build turned on, you can make some changes, hit the key, and Make will compile your code before it runs it.

You might notice that my build system specification also lists a Clean variant, but there is no such target anywhere in the sample Makefile. Usually a target like that would be the list of commands that remove all of the files that the Makefile is creating for you (in this case, main.o and sfml).

That kind of rule can be handy to “clean” the project, for example to force everything to rebuild no matter what the next time you build.

If you’re still awake, congratulations on making it all the way to the bottom of this post!

3 Likes

#3

As an addition to @OdatNurd’s little writeup about Makefiles, you can run multiple “commands” in a build, but only if your shell is capable of this (which they usually are). Just use shell_cmd instead of cmd and concatenate the commands with & or && (or ; even?).

That said, using a Makefile is the proper solution to this problem.

2 Likes

#4

Thanks, both :smiley:

I juste changed some little things :

SFML_DIR=/Volumes/DATA/SFML

LIBDIR=$(SFML_DIR)/lib

CFLAGS=-I$(SFML_DIR)/include

LIBS=-lsfml-graphics -lsfml-window -lsfml-system

default: sfml
LD_LIBRARY_PATH=$(LIBDIR) ./sfml

sfml: main.o
g++ -o sfml -L$(LIBDIR) $(LIBS) main.o

main.o: main.cpp
g++ -c main.cpp $(CFLAGS) -o main.o

run: sfml
LD_LIBRARY_PATH=$(LIBDIR) ./sfml

Works perfectly !!!

@FichteFoll : This is for the build of the project, huh ?

0 Likes