Cpp - linking prebuilt library with headers and multiple .so files

I am having difficulty understanding how to properly link prebuilt libraries during the linker process. I am trying to link several SFML libraries in order to build and execute a simple example taken from SFML’s tutorial page:

#include <SFML/Graphics.hpp>

int main() {
    sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
    sf::CircleShape shape(100.0f);

    shape.setFillColor(sf::Color::Green);

    while (window.isOpen()) {
        sf::Event event;

        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        window.clear();
        window.draw(shape);
        window.display();
    }

    return 0;
}

I have constructed my build.gradle file accordingly:

apply plugin: 'cpp'

model {
    repositories {
        libs(PrebuiltLibraries) {
            sfml {
                def libDir = '/usr/lib/x86_64-linux-gnu/'

                headers.srcDir '/usr/include'

                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file(libDir + 'libsfml-graphics.so')
                }

                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file(libDir + 'libsfml-window.so')
                }

                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file(libDir + 'libsfml-system.so')
                }
            }
        }
    }
}

model {
    components {
        helloSFML(NativeExecutableSpec) {
            binaries.all {
                cppCompiler.args '-std=c++14', '-Wall'
            }

            sources {
                cpp {
                    source {
                        srcDir "src"
                        include "**/*.cpp"
                    }

                    exportedHeaders {
                        srcDir "include"
                    }

                    lib library: "sfml"
                }
            }
        }
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.11'
}

When linking, I get the following error:

/home/dylangleason/Documents/Projects/gradle/custom_dependencies/build/objs/helloSFML/helloSFMLCpp/e1xohc1wndv4giuowwn7ptzq5/main.o: In function `main':              
main.cpp:(.text+0x93): undefined reference to `sf::VideoMode::VideoMode(unsigned int, unsigned int, unsigned int)'                                                    
main.cpp:(.text+0xc6): undefined reference to `sf::RenderWindow::RenderWindow(sf::VideoMode, sf::String const&, unsigned int, sf::ContextSettings const&)'            
main.cpp:(.text+0x100): undefined reference to `sf::CircleShape::CircleShape(float, unsigned long)'                                                                   
main.cpp:(.text+0x10c): undefined reference to `sf::Color::Green'                                                                                                     
main.cpp:(.text+0x114): undefined reference to `sf::Shape::setFillColor(sf::Color const&)'                                                                            
main.cpp:(.text+0x123): undefined reference to `sf::Window::isOpen() const'                                                                                           
main.cpp:(.text+0x144): undefined reference to `sf::Window::pollEvent(sf::Event&)'                                                                                    
main.cpp:(.text+0x161): undefined reference to `sf::Window::close()'                                                                                                  
main.cpp:(.text+0x187): undefined reference to `sf::Color::Color(unsigned char, unsigned char, unsigned char, unsigned char)'                                         
main.cpp:(.text+0x1a4): undefined reference to `sf::RenderTarget::clear(sf::Color const&)'                                                                            
main.cpp:(.text+0x1bb): undefined reference to `sf::RenderStates::Default'                                                                                            
main.cpp:(.text+0x1c6): undefined reference to `sf::RenderTarget::draw(sf::Drawable const&, sf::RenderStates const&)'                                                 
main.cpp:(.text+0x1d5): undefined reference to `sf::Window::display()'                                                                                                
main.cpp:(.text+0x1fd): undefined reference to `sf::RenderWindow::~RenderWindow()'                                                                                    
main.cpp:(.text+0x267): undefined reference to `sf::RenderWindow::~RenderWindow()'                                                                                    
/home/dylangleason/Documents/Projects/gradle/custom_dependencies/build/objs/helloSFML/helloSFMLCpp/e1xohc1wndv4giuowwn7ptzq5/main.o: In function `sf::CircleShape::~  
CircleShape()':                                                                                                                                                       
main.cpp:(.text._ZN2sf11CircleShapeD2Ev[_ZN2sf11CircleShapeD5Ev]+0xd): undefined reference to `vtable for sf::CircleShape'                                            
main.cpp:(.text._ZN2sf11CircleShapeD2Ev[_ZN2sf11CircleShapeD5Ev]+0x19): undefined reference to `vtable for sf::CircleShape'                                           
main.cpp:(.text._ZN2sf11CircleShapeD2Ev[_ZN2sf11CircleShapeD5Ev]+0x2d): undefined reference to `sf::Shape::~Shape()'                                                  
collect2: error: ld returned 1 exit status                                                                                                                            
                                                                                                                                                                      
:linkHelloSFMLExecutable FAILED                                                                                                                                       
                                                                                                                                                                      
FAILURE: Build failed with an exception. 

I’ve double-checked that path for the headers and dynamic libraries directory (/usr/include and /usr/lib/x86_64-linux-gnu, respectively), and those appear to be correct. The only other thing I can think of is the withType method is overwriting the value of sharedLibraryFile (not sure which scope this is declared in) and so only one dynamic library file is getting set.

Linking via the command line would be done like so: g++ main.o -o sfml-app -lsfml-graphics -lsfml-window -lsfml-system

But I am not sure how to translate this into gradle/groovy

It looks like I had to split up the SFML dynamic libraries into separate PrebuiltLibraries:


model {
    repositories {
        libs(PrebuiltLibraries) {
            sfml {
                headers.srcDir "/usr/include"
            }

            def libDir = "/usr/lib/x86_64-linux-gnu/"

            sfmlgraphics {
                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file(libDir + 'libsfml-graphics.so')
                }
            }

            sfmlwindow {
                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file(libDir + 'libsfml-window.so')
                }
            }

            sfmlsystem {
                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file(libDir + 'libsfml-system.so')
                }
            }
        }
    }
}

And then in my NativeExecutableSpec:

model {
    components {
        helloSFML(NativeExecutableSpec) {
            binaries.all {
                cppCompiler.args '-std=c++14', '-Wall'
            }

            sources {
        	cpp {
                    source {
                        srcDir "src"
        		include "**/*.cpp"
                    }

                    exportedHeaders {
			srcDir 'include'
                    }

                    lib library: "sfml", linkage: "api"
                    lib library: "sfmlgraphics"
                    lib library: "sfmlwindow"
                    lib library: "sfmlsystem"
		}
            }
	}
    }
}

This appears to have worked!

2 Likes

thank you very much, I tried to do something like that but I failed miserably…

Hi @Wabri, would you mind sharing what you tried so we can try a help you solve your issue? Maybe opening a new post would be a good idea.