Help with generating the wrappers
golddranks opened this issue · 25 comments
Hi, first of all, thanks for working this project. If I can be of any help with debugging, testing, or reporting bugs, I'm all in.
I have a working CppSharp build and QtSharp builds without problems. I have Qt 5.3.2 installed. The wrapper generation fails, as lib.FindCompleteClass("QString") (QtSharp.cs, row 76) returns null and there's a null dereferencing exception. If I circumvented that row, it manages to build QtCore.cs but it's almost empty:
//----------------------------------------------------------------------------
// This is autogenerated code by CppSharp.
// Do not edit this file or all your changes will be lost after re-generation.
//----------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace QtCore
{
}
It also builds some other files: QEventHandler.cs, QEventArgs.cs, MarshallQStrings.cs, DynamicQObject.cs, but there's some error messages in the console: QObject and QEvent can't be accessed.
I'll be happy to provide further info and debug further, if needed.
Btw. as of now, QtSharp asks for qmake path and make path. It directly inferences gcc path from make path, but on Windows systems, they aren't neccessarily the same: for example, I have a default MinGW+MSYS install, and my gcc path is C:\MinGW\bin\gcc.exe but my make path is C:\MinGW\msys\1.0\bin\make.exe. If QtSharp expects some unix tools to be installed anyway, maybe it could inference all the locations using the "which" tool?
Hello,
Please use the MinGW that comes with Qt. When I started the project, I wanted to make it as flexible as possible and this is why I allowed an arbitrary path to 'make'. However, I was recently able to witness that different MinGW installations require different tinkering in order for the generation to work. So the only configuration proven to work is Qt's built-in MinGW. It is of course fixable but I am afraid I have many tasks that are way more important than this one. What I can do in the short term is remove the option to pass a 'make' executable and replace it through extraction from the Qt set-up.
Another note: please take a look at the README in case you haven't yet. You need to add a path to your PATH.
@golddranks in my fork I started adding tests with nunit.
Thanks for the tip!
Using the make provided with Qt (confusingly not named "make.exe" but "mingw32-make.exe") helped! The problem was that my normal MinGW gcc returned the build target as nothing else than "mingw32", whereas the real target value should have been i686-w64-mingw32 in my case. The gcc provided with Qt returned the real target value.
The wrong target value caused it not to find the include files in the Qt dir, as the target value is part of their path.
Using the right target resolved the problem. But maybe we could add some simple tests or guards that could warn the user in cases like this? Or at least mention in the documentation that one should use the mingw32-make.exe that comes with Qt.
There was some other problems too:
- There was a broken reference to CppSharp.Parser. Removing that and adding a reference to CppSharp.Parser.CLI.dll fixed Visual studio nagging about it so the project would build.
- Even with the reference fixed, it complained runtime that it's unable to load CppSharp.Parser.CLI.dll or one of it's dependencies. Rebuilding CppSharp.Parser.CLI.dll and its dependency CppSharp.CppParser.dll from the CppSharp project AND setting the working directory to the References directory solved the problem. It seemed 1) not to find CppSharp.CppParser.dll, because it didn't search from the correct directory 2) there seemed to be some kind of clash between 32-bit and 64-bit binaries.
Your explanation is absolutely correct, this is precisely what happens.
You're right that I can quickly add a note in the README, I have some other work to do at the moment but I'll have it done tonight. About changes to the code, I think I'll implement my idea of extracting the 'make' from the Qt set-up but this is for later on.
Please accept my apologies about the incorrect references. The problem is that I often have to debug CppSharp and this is why I've added it as a Git sub-module over here. However, I cannot commit that because Joao, the maintainer of CppSharp, insists on using an external build tool which generated the C# project files and thus they are never committed to the repository. Consequently, I commit changes to QtSharp blindly and this sometimes blows up in my face, as in the current case. I'll check the references and fix them tonight as well.
No need to apologize! Thanks to you, I got Qt Core running on C#.
One more question: Is there any work done on Qt GUI and Qt Widgets yet? The generator generates wrappers only for Qt Core now, right? I tried to call the ConsoleDriver.Run for Qt5Gui.dll, but it has some problems with the headers again:
Error parsing 'QtGui'
C:\Qt\Tools\mingw482_32\i686-w64-mingw32\include\winnt.h(2268,7): error: unknown type name 'PCONTEXT'; did you mean '_CONTEXT'?
This error can be ignored, I believe. The problem is elsewhere. Wrappers need to have dependencies between them parallel to the dependencies of the wrapped libs. This hasn't been done in CppSharp yet. It's really high on my list but I've been unable to get to it because of paid jobs. I know exactly what must be done, I've just not had the time.
Could I help somehow?
Thank for your offer. Please note that it involves work on C++# as well. Here's what I think should be done in order to implement this feature:
- All libraries to wrap must be sorted so that libs that depend on none of their siblings are wrapped first. For example, if we take QtWidgets, QtGui and QtCore, they must be wrapped in the order QtCore, QtGui, QtWidgets. To sort them, use CppSharp.AST.NativeLibrary.Dependencies. The library objects are contained in Driver.Symbols.Libraries;
- Create a Dictionary containing the name of the native lib as the key and its wrapped assembly as the value and add each wrapped lib there. You should be able to get the compiled assembly from disk - take a look at Driver.CompileCode;
- In the same CompileCode method you need, by using the Dictionary from 2., to add the dependencies to compilerParameters.ReferencedAssemblies;
- Finally, you need to add the dependent name-spaces to DriverOptions.DependentNameSpaces. I think you should be able to get the name-space you need by loading each dependent assembly with reflection, getting any class and then getting its name-space.
Hi, I'm trying to work on this. (I know only little about the inner workings of C++# but I'll try to make sense of it!) Btw. the compilation of Qt5Gui.dll crashed already at the preprocessing stage: due to the include files having errors, it refused to parse QtGui and the lib.TranslationUnits count was 0. (Should be some hundreds?) I noticed that the error is fixed when you define a preprocessor macro X86. I think that the headers expect it to be defined, but clang (or whatever does the preprocessing and parsing) doesn't define it. Adding #define X86 to the start of winnt.h in Qt's mingw solved the problem, but there might be some more elegant way?
Trying to make sense of the dependency stuff now.
driver.Options.addDefine("X86"); in QtSharp.cs should work. See how _WIN32 is added.
Thanks, it works.
I might have found a bug either in CppSharp or in LLVM. When CppSharp's Parser::ParseSharedLib reads the dependencies to NativeLib->Dependencies, it has the iterable "dep" on row 3090, in Parser.cpp. However, with a .DLL file with multiple dependencies, it manages to read only the first one (for example Qt5Gui.dll has dependencies to many other DLL:s but CppSharp thinks it only has 3036 references to libgcc_s_dw2-1.dll, which is entirely wrong, as anybody can see, using this PEview tool: http://wjradburn.com/software/ and checking the section .idata of Qt5Gui.dll.). After investigation, it seems that LLVM's iterator on ImportDirectoryEntryRef does increment its "Index" value, but it doesn't ever even use that value, and stays all the time where it started. Do you think we should report this to LLVM? It seems odd that the iterator doesn't iterate, or then I'm missing something.
I know about this bug, I've sent a patch to LLVM but they haven't taken it because I haven't prepared a test for it. There is a "Fixed the getting of names and look-up entries of DLL imports.patch" for LLVM in CppSharp/patches. Please apply it and then rebuild CppSharp. I thought that was mentioned in the README but it isn't, I'll have Joao fix it.
Sorry for the delay. Getting the dependencies works now.
There was another patch, "type_traits_MSVC_12.patch", but I'm unable to apply it to the Clang commit that is recommended on the CppSharp page ( c785591d768074e1666bc306086588b1242d156c ) Should that be applied too?
I'm now able to get to the point where it's generating the code. It crashes with null point exception on CppSharp's FixDefaultParamValuesOfOverridesPass, on line 14 rootBaseMethod being null. Are you experiencing this crash too, or is there still something I have to fix with my build that I'd be on the same ground as you? Are you able to get the whole generation phase through?
If the patch causes problems, do not apply it, it's not relevant here because we use MinGW and not VC++. In fact, I think the type traits have been fixed in Clang so we should just delete it.
About the null ref exception: assuming you get it with QtCore, please put a breakpoint in CompileInlinesPass.VisitLibrary and make sure you get no error when compiling the inlines. If you do, check that the mingw32-make.exe you passed as a command line parameter works properly (there's a note in the README about adding the dir containing the make exe to your PATH). Once you have it fixed, the error should disappear.
No, QtCore wrapper gets generated without problems. It even works. (However, I didn't test anything but getting the Qt version using QtCore.QSysInfo.WindowsVersion. But at least the DLL loads correctly and the value is set and wrapped properly.) Path and the parameters are set up properly.
When generating QtGui, it crashes on CppSharp/src/Generator/Passes/FixDefaultParamValuesOfOverridesPass.cs:14. If try to help making QtGui work, trying to improve CppSharp with your directions, I want to know how far I am expected to get with the current wrapper generation so that I don't end up trying to solve problems that are already solved.
Thanks!
Allright, I did some proof-of-concept style thing with your directions: added the entries to DependentNameSpaces and ReferencedAssemblies. (No any fancy automatic sorting by dependencies or such implemented yet, I did it just QtGui- and QtCore-specifically to see if it works.)
It still crashes on the FixDefaultParamValuesOfOverridesPass. I investigated the problem, and it seems that GetRootBaseMethod from ClassExtensions.cs is unable to get the base method for method "itemData" in class QStandardItemModel.
It all boils down to the fact that it regards the return type of the base method, itemData in QAbstractItemModel different than of the derived method itemData in QStandardItemModel. Both return types are indeed QMaps, but still the type comparer fails. Both type datas are of type CppSharp.AST.QualifiedType, so there's something funny with the comparison of these types.
I am sorry about the misunderstanding. Now that I have a better grasp on the issue, could you please publish a branch with your work so that I can debug the problem?
I published my forks of CppSharp and QtSharp:
https://github.com/golddranks/CppSharp
https://github.com/golddranks/QtSharp
The QtSharp fork doesn't contain any significant code changes. CppSharp contains some changes, mostly for helping with debugging.
Excellent, thank you. I'll let you know as soon as I have some results.
Oops, btw. I made my minor changes with QtSharp to the branch QtGuiDebugging, for your information. With CppSharp, I commited directly to my copy of master.
I got past of FixDefaultParamValuesOfOverridesPass. It now crashes on GetterSetterToPropertyAdvancedPass, which is the final pass of the TranslationUnitPasses.
Nice work! Now I'd like to ask you to isolate that fix and send a pull to CppSharp itself. Joao will tell you if you need to change anything. He'll also ask you for a test if possible but in general these are details you'd better discuss with him.
Hi, I've recently created a fork as well as a couple of docs on getting things running on a windows / Visual Studio enviroment
https://github.com/garlicbready/QtSharp/wiki/QtSharp
https://github.com/garlicbready/QtSharp
I was having a bit of trouble with the CppSharp dll's in Studio so I also put together a quick doc on the method I've been using to compile it
https://github.com/garlicbready/QtSharp/wiki/CppSharp
I'll need to have an experiment with some of the patches mentioned further up in this thread
The changes I've made in the fork are mostly cosmetic
- moving things into directories / namespaces
- added a processor class / parameters class to split out the processing and detection of Qt directories
- simplified the CLI app a bit
- added NLog support instead of Console.writeline
- moved libs to be pulled via Nuget
- added a couple of try / catches just to get QtCore going
It's probably a bit too many to issue a pull request, as I'm not sure you'd want all those changes in anyway but some might be useful
so far I'm getting "could not load dll procedure could not be found" on most of the tests so I must have something wrong somewhere still
Hello @garlicbready. Thank you for your work. I've been trying to have @golddranks's work merged, once I've finished that, I'll take a look at your effort.
@golddranks I've been able to come up with a simpler fix for the property pass. Could you please send Joao a pull about the template equality fix? Once that is merged, I'll send him the fixed property pass.