Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to build C++ module as a shared library #2099

Closed
heraldofgargos opened this issue Jan 4, 2019 · 12 comments
Closed

Unable to build C++ module as a shared library #2099

heraldofgargos opened this issue Jan 4, 2019 · 12 comments

Comments

@heraldofgargos
Copy link

heraldofgargos commented Jan 4, 2019

Been following the latest documentation and I cannot compile the engine and a custom C++ module as a shared library on Windows 10 with MSVC 2017.

@akien-mga akien-mga added the bug label Jan 9, 2019
@logicor-cn
Copy link

logicor-cn commented Jan 28, 2019

I might have just hit the same problem.

Was following:
https://docs.godotengine.org/en/3.0/development/cpp/custom_modules_in_cpp.html#improving-the-build-system-for-development

Environment:
Godot 3.0.6-stable
Windows 10
VS 2015 CE
Scons 3.0.1

The build spew a ton of unresolved external symbol error as following:

register_types.windows.opt.tools.64.obj : error LNK2019: unresolved external symbol "void __cdecl _err_print_error(char const *,char const *,int,char const *,enum ErrorHandlerType)" (?_err_print_error@@YAXPEBD0H0W4ErrorHandlerType@@@Z) referenced in function "public: static void __cdecl ClassDB::register_class<class Dummy>(void)" (??$register_class@VDummy@@@ClassDB@@SAXXZ)
dummy.windows.opt.tools.64.obj : error LNK2001: unresolved external symbol "void __cdecl _err_print_error(char const *,char const *,int,char const *,enum ErrorHandlerType)" (?_err_print_error@@YAXPEBD0H0W4ErrorHandlerType@@@Z)

Since it is a dependency issue, I tried to comment out the following line from the tutorial:

# We don't want godot's dependencies to be injected into our shared library.
module_env['LIBS'] = []

And now it builds fine.

Maybe the MSVC requires some additional flag to defer symbol resolution to runtime?

@logicor-cn
Copy link

Correction, by removing the dependency library list clean up, I was able to build the shared library, but not the engine tools executable.

Latter failed with error:

[ 40%] Linking Shared Library ==> bin\aero_engine.windows.opt.tools.64.dll
[ 97%] Linking Program        ==> bin\godot.windows.opt.tools.64.exe
LINK : fatal error LNK1181: cannot open input file 'aero_engine.windows.opt.tools.64.windows.opt.tools.64.lib'
scons: *** [bin\godot.windows.opt.tools.64.exe] Error 1181

@logicor-cn
Copy link

logicor-cn commented Jan 28, 2019

Looks like there is something wrong around the following line also:

shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0]
  1. This line removes the extension part of the file name, which is behavior designed for gcc/clang. MSVC actually takes the file name with extension.
  2. Somewhere down the build system there is a unconditioned append of .windows.opt.tools.64.lib to the env['LIBS'] item. Thus even if I removed the rsplit part of above line to reserve the .dll extension, the library name actually passed to msbuild still got the extra .windows.opt.tools.64.lib suffix appended, which became aero_engine.windows.opt.tools.64.dll.windows.opt.tools.64.lib.

@logicor-cn
Copy link

logicor-cn commented Jan 28, 2019

It seems that scons is automatically appending the suffix mentioned above. Smells like another scons bug.

@akien-mga
Copy link
Member

See godotengine/godot#23769.

@logicor-cn
Copy link

logicor-cn commented Jan 28, 2019

@akien-mga Applying the patch on top of 3.0.6-stable did not work. 3.0 branch does not seem to have the commit either. master seems to have a changed module API so I did not quite bother.

On 3.0.6-stable, env['LIBSUFFIXES'] seems to be ['$LIBSUFFIX'] which is basically .lib alone anyway. So that patch seems to be in an opposite direction. I also notice that env['$SHLIBPREFIX'] being empty in my environment.

Still looking further.

@logicor-cn
Copy link

logicor-cn commented Jan 28, 2019

I think I am getting closer on this.

The first problem is that MSVC linker do no take dll as linker input, to link a dll, one have to instead link against the "import" lib generated accompany the actual dll. Thus the scons behavior of always trying to append that suffix when it is not a match to lib.

Now, according to scons docs

On Windows systems, the SharedLibrary builder method will always build an import (.lib) library in addition to the shared (.dll) library, adding a .lib library with the same basename if there is not already a .lib file explicitly listed in the targets.

But as I check my build, the import (.lib) library is not built, thus the problem.

@logicor-cn
Copy link

Traced into SCons/Tool/mslink.py and confirmed the "import" lib is added to extratargets in _dllEmitter() of scons. Yet the binary is not generated. Probably a bug of scons.

@logicor-cn
Copy link

logicor-cn commented Jan 28, 2019

Looks like reason of the missing "import" lib is my own lack of MSVC knowledge. Apparently you need to specify at least one __declspec(dllexport) function or class for the linker to have anything to export at all.

After fixing that, I am able to build dll for debug and release_debug target only, with the following modifification to SCsub:

  1. Comment out the following line:
module_env['LIBS'] = []
  1. Replace change rsplit to split in the following line.
shared_lib_shim = shared_lib[0].name.split('.',1)[0]

However, this does break again once I try to build release target for template, with the following error:

LIBCMT.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl __scrt_common_main_seh(void)" (?__scrt_common_main_seh@@YAHXZ)

(Building tools always have no problem because it does not support release target.)

After sometime of investigation, I found this is due to the hard coded /SUBSYSTEM:WINDOWS and /ENTRY:mainCRTStartup option fed to the linker under release target.

/~https://github.com/godotengine/godot/blob/8ac39d886307d76c286e804e027fc39f6b5aaac6/platform/windows/detect.py#L111

It looks like these options are added here solely for the executable, without taking dll module into consideration. Will open a bug for this in the godot project since this part is no longer a documentation issue.

Lastly, adding the following lines to SCsub would workaround the issue:

module_env['LINKFLAGS'] = [ flag for flag in module_env['LINKFLAGS'] if flag != '/ENTRY:mainCRTStartup' ]

@axsaucedo
Copy link

I can confirm this is still an issue in 3.2.3-stable

@johnyc90
Copy link

Same thing. Still present at 3.4.2.

@Calinou
Copy link
Member

Calinou commented Jan 29, 2022

Duplicate of godotengine/godot#15675.

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

No branches or pull requests

6 participants