Godot version: 3.1
OS/device including version: Windows
Issue description:
It's very likely to be my fault, but I can't include the FMOD library when linking a custom module.
It's strange how the module itself compiles without problems, but when it comes to the "Linking program" step the compiler freezes for a bit and then outputs fatal error LNK2019: unresolved external symbol "public: static enum FMOD_RESULT __cdecl FMOD::Studio::System::create(class FMOD::Studio::System * *,unsigned int)" in function "public: __cdecl FMod::FMod(void)".
Minimal reproduction project:
I placed the "FMOD Studio API Windows" under "thirdparty". The module itself basically contains just a call to FMOD's initialization function. I attached the module as a zip file.
For those who don't want to download the zip, here's the SCsub:
Import('env')
fmodapifolder = "#thirdparty/FMOD Studio API Windows/api"
module_env = env.Clone()
module_env.add_source_files(env.modules_sources, "*.cpp")
module_env.Append(CPPPATH=fmodapifolder + "/studio/inc")
module_env.Append(LIBPATH=fmodapifolder + "/studio/lib")
module_env.Append(CPPPATH=fmodapifolder + "/lowlevel/inc")
module_env.Append(LIBPATH=fmodapifolder + "/lowlevel/lib")
Here's fmod.cpp:
#include "fmod.h"
FMod::FMod() {
// Initialize fmod
FMOD::Studio::System* system = NULL;
FMOD::Studio::System::create(&system);
}
void FMod::_bind_methods(){
// none
}
Here's fmod.h:
#ifndef FMODNODE
#define FMODNODE
#include "scene/main/node.h"
#include "fmod.h"
#include "fmod.hpp"
#include "fmod_common.h"
#include "fmod_studio.hpp"
#include "fmod_studio.h"
#include "fmod_studio_common.h"
class FMod : public Node {
GDCLASS(FMod, Node);
protected:
static void _bind_methods();
public:
FMod();
};
#endif
Also, I don't know if this can help, but without any call to FMOD functions (only with the includes), scons compiles without any issue.
That's not a Godot issue, you just need to actually link the library by appending it to LIBS for your module_env (like module_env.Append(LIBS=['FMOD']) or similar). See http://docs.godotengine.org/en/latest/development/cpp/binding_to_external_libraries.html
If the docs are not clear enough for your use case, you can open an issue on https://github.com/godotengine/godot-docs to discuss it further and have the tutorial improved.
I have this issue too.
I have the same setup as @MicheleLambertucci and my SCsub is:
Import('env')
fmodapifolder = "#thirdparty/FMOD Studio API Windows/api"
module_env = env.Clone()
module_env.add_source_files(env.modules_sources, "*.cpp")
module_env.Append(CPPPATH=fmodapifolder + "/studio/inc")
module_env.Append(LIBPATH=fmodapifolder + "/studio/lib")
module_env.Append(CPPPATH=fmodapifolder + "/lowlevel/inc")
module_env.Append(LIBPATH=fmodapifolder + "/lowlevel/lib")
module_env.Append(LIBS=['fmod','fmodL','fmodstudio','fmodstudioL','fmod_vc','fmodL_vc','fmodstudio_vc','fmodstudioL_vc'])
Still I get Linker errors.
Note that the FMOD API is a shared library (so .lib and .dll files), and the both the docs and the engine use open source static libraries. So maybe this is not the correct way for binding an external Shared library? The docs don't say anything about it and the engine source code doesn't provide any example on how to do this.
Not an expert, but from what I remember .lib files distributed with shared libraries (or .a on linux) are exactly static libraries. They should do the loading of .dll for you when included in the executable.
@rmazzier You're close - the issue is that the libs have to be passed to the linker for the Godot binary, and thus to the main env. This should work:
fmodapifolder = "#thirdparty/FMOD Studio API Windows/api"
module_env = env.Clone()
module_env.add_source_files(env.modules_sources, "*.cpp")
module_env.Append(CPPPATH=fmodapifolder + "/studio/inc")
module_env.Append(CPPPATH=fmodapifolder + "/lowlevel/inc")
env.Append(LIBPATH=fmodapifolder + "/studio/lib")
env.Append(LIBPATH=fmodapifolder + "/lowlevel/lib")
env.Append(LIBS=['fmod','fmodL','fmodstudio','fmodstudioL','fmod_vc','fmodL_vc','fmodstudio_vc','fmodstudioL_vc'])
Here's a test module I used (on Linux) to confirm that:
sndfile.zip
module_env = env.Clone()
module_env.Append(CPPPATH=["#modules/sndfile/sndfile/include"])
env.Append(LIBPATH=["#modules/sndfile/sndfile/lib"])
env.Append(LIBS=["sndfile"])
# Special case here as sndfile depends on FLAC and vorbis
env.Append(LIBS=["FLAC", "vorbis", "vorbisenc"])
Thank you for your reply.
Even if I had already tried the way you suggested, I gave it another chance. My current SCsub is:
Import('env')
fmodapifolder = "#thirdparty/fmod/"
module_env = env.Clone()
module_env.add_source_files(env.modules_sources, "*.cpp")
module_env.Append(CPPPATH=[fmodapifolder + "/studio/inc/"])
module_env.Append(CPPPATH=[fmodapifolder + "/lowlevel/inc/"])
env.Append(LIBPATH=[fmodapifolder + "/studio/lib/ "])
env.Append(LIBPATH=[fmodapifolder + "/lowlevel/lib/"])
env.Append(LIBS=['fmodstudio_ARM','fmodstudio_X64','fmodstudioL_ARM','fmodstudioL_X64'])
env.Append(LIBS=['fmod_ARM','fmod_X64','fmodL_ARM','fmodL_X64'])
But I still get linker errors. Specifically:
D:\Riccardo\Godot Build\godot-master>scons -j6 platform=windows
scons: Reading SConscript files ...
Configuring for Windows: target=debug, bits=default
Found MSVC compiler: amd64
Compiled program architecture will be a 64 bit executable (forcing bits=64).
YASM is necessary for WebM SIMD optimizations.
WebM SIMD optimizations are disabled. Check if your CPU architecture, CPU bits or platform are supported!
Checking for C header file mntent.h... (cached) no
scons: done reading SConscript files.
scons: Building targets ...
[ 97%] [91mLinking Program [95m==> [93mbin\godot.windows.tools.64.exe[0m
sibi[ 98%] le aprire il file di input 'fmodstudio_ARM.windows.tools.64.lib'
[100%] progress_finish(["progress_finish"], [])
[100%] scons: *** [bin\godot.windows.tools.64.exe] Error 1181
scons: building terminated because of errors.
Since I am not understanding whether I am doing something wrong or not , would you mind trying to compile it and see if you get the same error?
Here is the zip with the libs and my current code.
Thanks.
[ 98%] le aprire il file di input 'fmodstudio_ARM.windows.tools.64.lib'
What Godot commit are you building against? And what SCons version? This extra lib suffix should be fixed in the master branch already with #20380.
Master branch, latest commit.
Using the latest SCons version:
D:\Riccardo\Godot Build\godot-master>scons --version
SCons by Steven Knight et al.:
script: v3.0.1.74b2c53bc42290e911b334a6b44f187da698a668, 2017/11/14 13:16:53, by bdbaddog on hpmicrodog
engine: v3.0.1.74b2c53bc42290e911b334a6b44f187da698a668, 2017/11/14 13:16:53, by bdbaddog on hpmicrodog
engine path: ['C:\\Python27\\scons-3.0.1\\SCons']
Copyright (c) 2001 - 2017 The SCons Foundation
Alright, it works fine on Linux but apparently #20045 is still valid on MSVC. Any idea @garyo?
We're now properly saving the original LIBSUFFIX and SHLIBSUFFIX in LIBSUFFIXES prior to modifying them, but MSVC's linker still seems to try LIBSUFFIX instead of iterating LIBSUFFIXES as hinted by the man page? https://github.com/godotengine/godot/blob/master/SConstruct#L425-L429
I found the cause of the issue. It is caused by different format in which windows and *nix linkers take their arguments.
On *nix systems, linkers take their arguments stripped from their prefixes and suffixes. This means that linker passed -lmylib argument actually looks for either libmylib.a or libmylib.so by default. $LIBPREFIXES and $LIBSUFFIXES are the variables that control which prefixes and suffixes the linker checks for.
MSVC linker, on the other hand, expects the arguments to be full filenames. So what SCons passes to the linker here is list of files that is constructed from list of libraries in$LIBS variable with $LIBLINKPREFIX and $LIBLINKSUFFIX prepended and appended respectively. And since $LIBLINKSUFFIX by default points to $LIBSUFFIX, we get error messages such as LINK : fatal error LNK1181: cannot open input file 'fmodL_vc.windows.opt.tools.32.lib'
There is a way, however, to override how the arguments that get passed to the linker are formatted. I'd suggest emulating the *nix linker behaviour on windows so that $LIBPREFIXES and $LIBSUFFIXES would work the same way on all platforms.
I overcame this when linking mono by passing the LINKFLAGS directly.
@neikeq Looking at your code right now. Yeah, that's also a way to go around it. Maybe it would be even better solution than the one I implemented - just wrap this piece of code in custom env functions.
Reopening as it's not properly fixed yet - see #23910.
I'm having the same issue here. Trying to link FMOD using MSVC 2017.
[100%] LINK : fatal error LNK1181: cannot open input file 'fmod_vc.windows.tools.64.lib'
scons: *** [bin\godot.windows.tools.64.exe] Error 1181
scons: building terminated because of errors.
Glad to see the issue mentioned here. Can somebody please suggest a temporary solution to this until it's properly fixed?
A temporary solution would be - as dumb as it sounds - renaming your libraries to match the Godot extensions, i.e. turn your fmod_vc.lib to fmod_vc.windows.tools.64.lib. If you are building on multiple configurations, you'd need to do have a copy of a library with each configuration's specific extension.
The other way would be taking a look at how neikeq did it with Mono.
https://github.com/godotengine/godot/blob/d8c40bccbbbf74001cbd085da5f71180e054e17f/modules/mono/config.py#L113-L119
However, I am not sure how confident you are with SCons/Python. Let me know if you need some more help.
This is the first time I'm being exposed to the SCons build system and I'm still getting used to it. Renaming the files worked however and it compiled without any errors 馃帀
I can confirm this is still an issue, its looking for the godot lib extensions for my libraries.
Using LINKFLAGS worked, but its not a very graceful solution.