• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
taylorsnead

Can't resolve problematic dlopen() call.

15 posts in this topic

I've been working mainly in Windows with VC11, but a few days ago switched to using MinGW (I had already been planning on switching, I just liked Visual Studio's plugins too much). Very quickly, I then installed GCC/G++ 4.7 on my Linux (Mint). Making a launcher executable for my library (This makes it easier for separation, or changing which library is launched without recompiling a large amount of code), I use Boost.Extension's shared_library (which simply uses LoadLibrary and dlopen (depending on the platform)) to load my dynamic/shared library (SFGame.so). This worked great on windows with both compilers, but on Linux, dlopen will fail however I use the path. Using the same path, Boost.Filesystem confirms (through the application) that the file can be accessed with the paths I'm using. My simple code: ("<" and ">" replaced with "^")
[source lang="cpp"]#include "iostream"
#include "functional"
#include "boost/extension/shared_library.hpp"
#include "boost/filesystem.hpp"

#if _WIN32 || _WIN64
# define EXT ".dll"
#elif __APPLE__
# define EXT ".dylib"
#elif __linux
# define EXT ".so"
#endif

int main( void )
{
using namespace boost::extensions;
using namespace boost::filesystem;

std::string libpath = "./SFGame.so";
path pfile( libpath );
if( exists( pfile ) )
{
std::cout ^^ "Game library: " ^^ complete( pfile ).generic_string() ^^ " exists\nSize: " ^^ file_size( pfile ) ^^ "\n";
}

shared_library lib( libpath );
if( !lib.open() )
{
std::cout ^^ "Failed to load " ^^ libpath ^^ "\n" ^^ dlerror() ^^ "\n";
return 0;
}

lib.get^void^( "Launch" )();

return 1;
}[/source]
This same code works perfectly on Windows, as I said. My output:
../../BinLinux//SFGame.so: cannot open shared object library
or:
SFGame.so: cannot open shared object library
depending on whether I use "./SFGame.so" (I assume because my Code::Blocks project file and main.cpp are in "Engine/Code/Game/" and SFGame.so is in "Engine/BinLinux/") or "SFGame.so". I can use the full path from "complete(pfile).generic_string()", which gives the same dir in the error as "./SFGame.so". Any ideas on how I could fix this from failing EVERY time? I even tried linking Launcher to Engine.so in the compiler (GNU GCC (well, g++) within Code::Blocks), but no dice. Edited by taylorsnead
0

Share this post


Link to post
Share on other sites
Have you tried setting LD_LIBRARY_PATH to contain the directory containing the library (and removing the ./ in the library name)? The dynamic link interpreter (probably ld.so) has some rules about locating shared objects that are not the same as the rules the shell follows when launching executables.

If that fails, try using '[font=courier new,courier,monospace]strace -e trace=open[/font] [i][font=courier new,courier,monospace]appname[/font][/i]' when running your launcher to see exactly the paths the loader is actually trying to open.
0

Share this post


Link to post
Share on other sites
I should have mentioned that, yes, I already tried setting LD_LIBRARY_PATH, and that didn't help either. It seems that at compile-time, the string passing to the dlopen gets set to that path local to the main.cpp. strace shows that it is trying to open that directory, not just displaying it, whereas filesystem is really opening the correct directory (which I already knew since it showed it). I don't know how to get it using the correct path, unless I moved my source to the folder where it should compile, but that seems like a horrible solution.
EDIT: Or it has something to do with the "Execution Working Dir" Option in Code::Blocks. I've tried setting that relatively and absolutely to BinLinux, but no change. Edited by taylorsnead
0

Share this post


Link to post
Share on other sites
Perhaps it's worth removing the IDE from the equation for the time being. One you've built the host program and the .so, does it work (with or without LD_LIBRARY_PATH modifications) if you run it from a command shell?

If so, it may be the case that your IDE is setting the working directory inappropriately before exec()ing the process.
1

Share this post


Link to post
Share on other sites
Okay, it seems like that was correct, though it seems that I do have to use an absolute path to the file, it works when compiled via terminal using g++-4.7, not using LD_LIBRARY_PATH (though I guess that would allow me to use relative paths). Code::Blocks still has the problem with the execution directory empty. Any thoughts on how to fix this? I guess I could just compile my Launcher with the terminal when I need to, but I'd prefer to be able to compile with my IDE (especially since it works fine on Windows, I feel like there should be an easy way to resolve this). It also seems like the same problem occurs with two dynamic libraries linked at compile/link time (of course, through Code::Blocks) (I use my Launcher as an executable to run my Game.so, which uses Engine.so to run and control the other, lower-level libraries (boost, glfw, alut, etc), so dynamic linking is important (though I use static linking when possible)).
0

Share this post


Link to post
Share on other sites
[quote name='taylorsnead' timestamp='1344909049' post='4969285']
Code::Blocks still has the problem with the execution directory empty. Any thoughts on how to fix this?
[/quote]

What do you mean by an empty execution directory? Whether you compile the your code from within your IDE or use the same commands from a shell, you should end up with an identical executable (except for internal timestamps, etc).

What is probable is that Code::Blocks has an option to specify the working directory for processes when you launch/debug them through the IDE. This would not be an option that effects the resulting binary in any way. So, just checking: do you understand the concept of a working directory (aka current directory aka current working directory :))?
1

Share this post


Link to post
Share on other sites
Oh, I mean, Code::Blocks has an option for "Execution working dir", and I tried it empty, but the same problem occurred. Running the binary result either through the IDE or from the terminal makes no difference, unless I compile it via terminal. That is why the option seemed suspicious to me. Through this, I should think I do understand "working directory" as it would be used for file paths within the executable. Despite these, I don't know how the problem persists even using an absolute directory to the file, but I feel it's something with libdl.so, and less to do with working directory, but I have no idea what to do about it.
0

Share this post


Link to post
Share on other sites
I can pretty much guarantee that if there was such a glaring bug in dlopen() it would have been noticed and fixed some time in the last 20, 30, or 40 years. that should be a hint as to where the problem isn't.

Does strace show a fail when opening the shared object even when you use an absolute path? Are there additional symbols thatneed resolving in the dlopened object, and they're not getting resolved in the particular load set you're using from the IDE? Is there an architecture problem (you can not use 64-bit DSOs from a 32-bit app, and the reverse is usually problematic as well)?

Does it work properly if you set LD_PRELOAD to your DSO? Does setting LD_WARN spew warnings? Have you tried setting LD_DEBUG (hint: try LD_DEBUG=help first)?
0

Share this post


Link to post
Share on other sites
Now, using full strace (just "strace ./Launcher"), it seems that it detects the file correctly with an absolute path, but then it does a few things, and then it tries opening the file with some relative directory that wouldn't be correct anyways. This is the part of the output that applies:

brk(0) = 0x1310000
brk(0x1331000) = 0x1331000
open("/home/taylorsnead/Documents/ShadowFox/NewEngine/BinLinux/SFGame.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300!\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=27024, ...}) = 0
mmap(NULL, 2122168, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f8d2ab03000
mprotect(0x7f8d2ab09000, 2093056, PROT_NONE) = 0
mmap(0x7f8d2ad08000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5000) = 0x7f8d2ad08000
close(3) = 0
open("../../BinLinux//SFEngine.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
munmap(0x7f8d2ab03000, 2122168) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8d2bcfe000
write(1, "Failed to load /home/taylorsnead"..., 82Failed to load /home/taylorsnead/Documents/ShadowFox/NewEngine/BinLinux/SFGame.so
) = 82
write(1, "../../BinLinux//SFEngine.so: can"..., 87../../BinLinux//SFEngine.so: cannot open shared object file: No such file or directory
) = 87

But, I don't know where it gets this new directory. Even using a relative directory, as with Boost.Filesystem, it sees the file, but dlopen (I guess) just converts it to a directory relative to the code/project files, which won't work with the executable. I'm using the same compiler for the libraries and executable, all (I guess, I don't specify to the compiler (G++)) 32-bit. Trying "LD_PRELOAD=SFGame.so /bin/ls" just says that SFGame.so can't be preloaded:
ERROR: ld.so: object 'SFGame.so' from LD_PRELOAD cannot be preloaded: ignored.
Using LD_PRELOAD with the path to Launcher instead of ls makes it run Launcher, which of course fails. Setting it without a path doesn't change the result of the strace of Launcher. Edited by taylorsnead
0

Share this post


Link to post
Share on other sites
[quote name='taylorsnead' timestamp='1344980969' post='4969606']
Oh, I mean, Code::Blocks has an option for "Execution working dir" [...] Through this, I should think I do understand "working directory" as it would be used for file paths within the executable.
[/quote]
If I understand its purpose, this option should [b]not[/b] affect the resulting [b]executable[/b]. Rather, it will only affect the working directory with which the [b]process[/b] is launched through the IDE. It is an option that affects [b]running [/b]the compiled code, not compiling it in the first place.


[quote name='taylorsnead' timestamp='1344984822' post='4969630']
Now, using full strace (just "strace ./Launcher"), it seems that it detects the file correctly with an absolute path, but then it does a few things, and then it tries opening the file with some relative directory that wouldn't be correct anyways.
[/quote]

That relative directory is likely the working directory. Again, are you sure you understand the concept?

Do "man getcwd" and use it to print the working directory at the start of your program. Does it match the directory in which your shared object resides?
1

Share this post


Link to post
Share on other sites
getcwd(), in fact, does output the correct directory when launching from terminal and not the IDE (Which is what I do anyway).
0

Share this post


Link to post
Share on other sites
I had already done that with relative and absolute directories, the correct dir, and setting the dir to empty. Either way doesn't work.
0

Share this post


Link to post
Share on other sites
Can you do a binary diff of the file built in the IDE against the file built in a command shell?

Have you tried examining the difference between the build commands when you build in the IDE vs in a command shell?
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0