CppSharp icon indicating copy to clipboard operation
CppSharp copied to clipboard

CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS does not work for "external return decl" ignored on Windows (MSVC)

Open qingfengxia opened this issue 3 years ago • 3 comments

Brief Description

I had fairly big C++ project to wrap into C#, it works mostly on Linux with dotnet 3.1, but not on Windows https://bitbucket.org/fathomteam/moab/src/master/

Because the target c++ headers do not use __declspec(dllexport) at all, and there are too much work to add them. I wonder whether CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS could be a solution, if not why.

Instead of CppSharp user manual's solution

If you're exposing C++ functions on Windows, you'll have to add the __declspec(dllexport) directive, otherwise the symbols won't be found when calling them from the managed world. You could also add the directive to a class directly, like this:

class __declspec(dllexport) ExposedClass
{
  // class definition
}

a quick solution by CMake is tried

    if(MSVC)
        set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
    endif()

Symbols are exported into dll, but got lots of warning, almost half API are not generated. E.g.

CppSharp warning:

Function 'get_coords' was ignored due to external return decl

The target C++ API virtual ErrorCode get_coords( const Range& entity_handles, double* coords ) const;

Actually, the return type enum has been correctly generated as public enum ErrorCode: uint on Linux, public enum ErrorCode on Windows

=== Related CppSharp code

// Generator/Passes/CheckIgnoreDecls.cs
private bool HasInvalidType(Type type, Declaration decl, out string msg)
{
    // ... skipped 
    var module = decl.TranslationUnit.Module;
    if (Options.DoAllModulesHaveLibraries() &&
        module != Options.SystemModule && ASTUtils.IsTypeExternal(module, type))
    {
        msg = "external";
        return true;
    }
}
   
// ASTUtils.IsTypeExternal
public static bool IsTypeExternal(Module module, Type type)
{
    var typeModule = type.GetModule();
    return typeModule != null && typeModule.Dependencies.Contains(module);
}

a hack to disable/skip this return type check failed with assertion

                if (HasInvalidType(ret.Type, function, out msg) && false) // tmp diasable this
                {
                    function.ExplicitlyIgnore();
                    Diagnostics.Debug("Function '{0}' was ignored due to {1} return decl type {2}",
                        function.Name, msg, ret);
                    return false;
                }

Vtable assertion in ClassLayout.cs failed Debug.Assert(Kind == VTableComponentKind.FunctionPointer);

OS: Windows

Used headers

https://bitbucket.org/fathomteam/moab/src/master/src/moab/Core.hpp https://bitbucket.org/fathomteam/moab/src/master/src/moab/Types.hpp

Used settings

Target: MSVC/

Other settings

Stack trace or incompilable generated code

qingfengxia avatar Feb 25 '21 09:02 qingfengxia

Would you be able to extract just the offending piece of C++ as the header? Makes testing much easier.

ddobrev avatar Mar 01 '21 19:03 ddobrev

Thank you, I may try debug it again.

I just do not understand, what is external type and external return decl.

The different on set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) and __dllspec(export).

qingfengxia avatar Mar 03 '21 15:03 qingfengxia

My understanding is: On every platform, clang is used to parse c++ headers, libraries files, not per-platform G++/MSVC compilers. So, on Windows, MingW32 ABI is not supported.

I just add __dllspec(export) to some class header files, it helps, even CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS is still used for MSVC to build DLL

I have modify the CppSharp, monkey patch to bypass some skipping, and generated the API I needed. Generator/Passes/CheckIgnoredDecls.cs

           if (HasInvalidType(ret.Type, function, out msg)) // tmp by pass this if_condition does not work
            {
                if(ret.ToString().Contains("moab.ErrorCode"))  // working
                    return true;
                if(ret.ToString().Contains("moab.Range.const_iterator"))  // working
                    return true;
                if(ret.ToString().Contains("moab.Range"))  // working
                    return true;
                function.ExplicitlyIgnore();
                Diagnostics.Debug("Function '{0}' was ignored due to {1} return decl type {2}",
                    function.Name, msg, ret);
                return false;
            }

There is other errors, I will open another issue.

Thank you

qingfengxia avatar Mar 12 '21 09:03 qingfengxia