Forum discussion related to f2f71d0dc7bb87
and my follow-up question to uwe in
https://github.com/FreeCAD/FreeCAD/commit/f2f71d0dc7bb87048933549c4919809a9781aa15#commitcomment-70279649
The hardest part is figuring out what your “plugin directory” is. On linux-mint, libFreeCAD_widgets.so goes into “/lib/x86_64-linux-gnu/qt5/plugins/designer”.
Couldn’t cmake be used for this?
In the cmake/Qt5Designer/Qt5DesignerConfig.cmake file, each designer plugin needs to populate it’s configuration through the _populate_Designer_plugin_properties makro.
I think, a get_property or get_target_property call for the IMPORTED_LOCATION_${CONFIGURATION} value could be used to get the locations where to install plugins.
ab2461629c
Yes, this works but it’s very odd that you have to know about a specific designer plugin in order to get that path.
Here is the process I use to to install the QTDesigner plugins on macOS (M1 version), if anyone is interested.
QT5 is installed via homebrew, this is the same version I use to build FC
brew install qt@5
No need to download and install the QTCreator app, QTDesigner comes bundled with the qt@5 homebrew install and is located at
/opt/homebrew/opt/qt@5/libexec/Designer.app -> is an alias and points to -> /opt/homebrew/Cellar/qt@5/5.15.3/libexec/Designer.app
The qmake for this QT@5 version is located at
/opt/homebrew/opt/qt@5/bin/qmake -> /opt/homebrew/Cellar/qt@5/5.15.3/bin/qmake
Following the tutorial from the Wiki to compile and install the Qt designer plugin for Linux:
cd freecad-source/src/Tools/plugins/widget
/opt/homebrew/opt/qt@5/bin/qmake plugin.pro
make
This produces a libFreeCAD_widgets.dylib file, which needs to be copied to the /plugin/designer folder
sudo cp libFreeCAD_widgets.dylib /opt/homebrew/opt/qt@5/plugins/designer
Now start the QTDesigner app under /opt/homebrew/opt/qt@5/libexec/Designer.app and the FC View Widgets and Preference Widgets are available in the sidebar.
Yes, you are right here. I read the information in the wiki after writing this and AFAICS the plugins for designer are to be installed into ${QT_DIR}/plugins/designer. So the only value that needs to be known is the root dir of the Qt installation. No need to know the name of a specific plugin being installed.
I found this example https://github.com/qgis/QGIS/blob/master/CMakeLists.txt that uses qmake to determine the plugin path.
qmake -query QT_INSTALL_PLUGINS
0b44a6c28d
Thanks Werner. I want to update the documentation on how to compile:
https://wiki.freecadweb.org/Compile_on_Windows#Qt_Designer_plugin
What is now different/what do I have to do to compile the plugin?
I found this example https://github.com/qgis/QGIS/blob/master/CMakeLists.txt that uses qmake to determine the plugin path.
qmake -query QT_INSTALL_PLUGINS0b44a6c28d
Just noticed, this is used already in the CMakeLists.txt file of the src/Tools/plugins/widget directory.
Seeing there’s already a cmake file for the plugin, what do you think about adding a build time option (defaults to OFF) to FreeCAD to be able to build and install the plugin on demand, without the need to manually build and install the plugin outside of package managers control? The CMakeLists.txt file already looks very good, it just overrides the CMAKE_INSTALL_PREFIX, which needs to be fixed eventually. I can try to get this working, if this proposal is agreed upon.
Edit: This would also simplify the documentation on how to build and install the plugin.
What is now different/what do I have to do to compile the plugin?
Instead of using qmake which many people apparently are not familiar with it’s now possible to use CMake as an alternative. On Linux and presumably macOS you only have to run cmake and make to build the plug-in and optionally run make install (which requires root permission).
On Windows you at least have to specify the paths to the CMake directory of a Qt installation or the Qt version of the LibPack (I haven’t tested it there so far).
Seeing there’s already a cmake file for the plugin, what do you think about adding a build time option (defaults to OFF) to FreeCAD to be able to build and install the plugin on demand, without the need to manually build and install the plugin outside of package managers control?
Sure, we could do that.
The CMakeLists.txt file already looks very good, it just overrides the CMAKE_INSTALL_PREFIX, which needs to be fixed eventually
Yes, this override of CMAKE_INSTALL_PREFIX has to be reverted.
Edit: This would also simplify the documentation on how to build and install the plugin.
The only difficulty I see is how to manage to also install the plugin? This would require root permission on many systems but it’s considered a bad idea to build FreeCAD as root. Furthermore, the plugin is only of interest for developers but not the user.
So, my suggestion would be to disable the install() target of the plugin when it’s built as a sub-project of FreeCAD and enable it when it’s built standalone. To the output a message with the path of the plugin directory should be written so that a developer can copy the file manually.
on macOS, the compile procedure gives an error during make (latest commit #7d843b2 on master)
# move to the directory where the widget is located
cd freecad-source/src/Tools/plugins/widget
cmake succedes:
# use cmake and specify the path to the qt@5 libraries
➜ widget git:(main) ✗ cmake -DCMAKE_PREFIX_PATH="/opt/homebrew/opt/qt@5" .
-- The C compiler identification is AppleClang 13.0.0.13000029
-- The CXX compiler identification is AppleClang 13.0.0.13000029
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Plugin will installed to: /opt/homebrew/Cellar/qt@5/5.15.3/plugins/designer
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget
make fails:
➜ widget git:(main) make
[ 20%] Automatic MOC for target FreeCAD_widgets
AutoMoc subprocess error
------------------------
The moc process failed to compile
"SRC:/plugin.h"
into
"SRC:/FreeCAD_widgets_autogen/EWIEGA46WW/moc_plugin.cpp"
Command
-------
/opt/homebrew/opt/qt@5/bin/moc -DFreeCAD_widgets_EXPORTS -DQT_CORE_LIB -DQT_DESIGNER_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_UIPLUGIN_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -I/Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget -I/opt/homebrew/opt/qt@5/lib/QtCore.framework -I/opt/homebrew/opt/qt@5/lib/QtCore.framework/Headers -I/opt/homebrew/opt/qt@5/mkspecs/macx-clang-arm64 -I/opt/homebrew/opt/qt@5/lib/QtWidgets.framework -I/opt/homebrew/opt/qt@5/lib/QtWidgets.framework/Headers -I/opt/homebrew/opt/qt@5/lib/QtGui.framework -I/opt/homebrew/opt/qt@5/lib/QtGui.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/System/Library/Frameworks/OpenGL.framework/Headers -I/opt/homebrew/opt/qt@5/lib/QtDesigner.framework -I/opt/homebrew/opt/qt@5/lib/QtDesigner.framework/Headers -I/opt/homebrew/opt/qt@5/lib/QtXml.framework -I/opt/homebrew/opt/qt@5/lib/QtXml.framework/Headers -I/opt/homebrew/opt/qt@5/lib/QtUiPlugin.framework -I/opt/homebrew/opt/qt@5/lib/QtUiPlugin.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/include/c++/v1 -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -F /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/System/Library/Frameworks -F /opt/homebrew/opt/qt@5/lib --include /Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget/FreeCAD_widgets_autogen/moc_predefs.h --output-dep-file -o /Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget/FreeCAD_widgets_autogen/EWIEGA46WW/moc_plugin.cpp /Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget/plugin.h
Output
------
/Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget/plugin.h:32: Error: Undefined interface
make[2]: *** [CMakeFiles/FreeCAD_widgets_autogen] Error 1
make[1]: *** [CMakeFiles/FreeCAD_widgets_autogen.dir/all] Error 2
make: *** [all] Error 2
Is there any additional setting which needs to be piped to cmake?
The only difficulty I see is how to manage to also install the plugin? This would require root permission on many systems but it’s considered a bad idea to build FreeCAD as root. Furthermore, the plugin is only of interest for developers but not the user.
So, my suggestion would be to disable the install() target of the plugin when it’s built as a sub-project of FreeCAD and enable it when it’s built standalone. To the output a message with the path of the plugin directory should be written so that a developer can copy the file manually.
There might be users which are developers as well and vice versa. My suggestion is not targeted at the usual user who compiles FreeCAD for itself and probably runs it from the build directory or installs it into it’s HOME directory, but rather to package maintainers, like myself. For this, the option would default to OFF, so a user doesn’t have to care for it. The package managers on the various distros (apt, dnf, yum, portage, pkgbuild, etc.) usually always have to run with root privileges, so there’s no issue with that from my point of view.
Disabling the install when built as a sub-project would contradict my suggestion. Like I said, the target audience for this change isn’t the user, but package maintainers who can decide whether to include the plugin in their builds. For example on Gentoo, if I add an option to the package to enable / disable the plugin, the users can decide whether they want it built and installed or not. In any case, all files will be under control of portage, the package manager. If the user also develops for FreeCAD, the designer files are also controlled by the package manager, while in your suggestion, the user has to bypass the package manager to install the plugin so that designer can find it. Usually designer plugins, like from KDE, quarter, qscintilla are installed through the package manager on Gentoo.
on macOS, the compile procedure gives an error during make (latest commit #7d843b2 on master)
make fails:/Users/dirkolbrich/FreeCAD/freecad-source/src/Tools/plugins/widget/plugin.h:32: Error: Undefined interfaceIs there any additional setting which needs to be piped to cmake?
Do you have designer installed? I had the same issue, when I was testing a patch and commented the find_package(Qt5Designer) from the CMakeLists.txt file.
Do you have designer installed? I had the same issue, when I was testing a patch and commented the find_package(Qt5Designer) from the CMakeLists.txt file.
Yes, QTDesigner is installed, it comes with the qt@5 library installed via homebrew.
No need to download and install the QTCreator app, QTDesigner comes bundled with the qt@5 homebrew install and is located at:
/opt/homebrew/opt/qt@5/libexec/Designer.app -> is an alias and points to -> /opt/homebrew/Cellar/qt@5/5.15.3/libexec/Designer.app
Edit: commenting the line find_package(Qt5Designer REQUIRED) in freecad-source/src/Tools/plugins/widget/CMakeLists.txt out does not solve the error.
Seems I solved the make error.
changed Line 24 in freecad-source/src/Tools/plugins/widget/plugin.h.
- #include <QtDesigner>
+ #include <QtUiPlugin>
QTDesigner/QDesignerCustomWidgetCollectionInterface is marked as deprecated, instead use QtUiPlugin/QDesignerCustomWidgetCollectionInterface.
make install builds and installs the created plugin correctly:
-- Installing: /opt/homebrew/Cellar/qt@5/5.15.3/plugins/designer/libFreeCAD_widgets.dylib
The package managers on the various distros (apt, dnf, yum, portage, pkgbuild, etc.) usually always have to run with root privileges
OK, if this is the case then it’s fine for me.
changed Line 24 in freecad-source/src/Tools/plugins/widget/plugin.h.
Still works here, so 156cf62b8a
libFreeCAD_widgets.dylib
Out of curiosity do other designer plugins also have the suffix .dylib? IIRC I once read that under macOS normal shared libraries have the .dylib suffix but real plugins use .so as under Linux. Is this correct?
I don’t know about the specifics of library file endings Linux vs. macOS, but in this case there is only a .dylib file crated, no .so file. The complete qt@5/plugins/ folder contains only .dylib files.
.
├── assetimporters
│ ├── libassimp.dylib
│ └── libuip.dylib
├── audio
│ └── libqtaudio_coreaudio.dylib
├── bearer
│ └── libqgenericbearer.dylib
├── canbus
│ ├── libqtpassthrucanbus.dylib
│ ├── libqtpeakcanbus.dylib
│ ├── libqttinycanbus.dylib
│ └── libqtvirtualcanbus.dylib
├── designer
│ ├── libFreeCAD_widgets.dylib
│ └── libqquickwidget.dylib
├── gamepads
│ └── libdarwingamepad.dylib
├── generic
│ └── libqtuiotouchplugin.dylib
├── geometryloaders
│ ├── libdefaultgeometryloader.dylib
│ └── libgltfgeometryloader.dylib
├── geoservices
│ ├── libqtgeoservices_esri.dylib
│ ├── libqtgeoservices_itemsoverlay.dylib
│ ├── libqtgeoservices_mapbox.dylib
│ ├── libqtgeoservices_mapboxgl.dylib
│ ├── libqtgeoservices_nokia.dylib
│ └── libqtgeoservices_osm.dylib
├── iconengines
│ └── libqsvgicon.dylib
├── imageformats
│ ├── libqgif.dylib
│ ├── libqicns.dylib
│ ├── libqico.dylib
│ ├── libqjpeg.dylib
│ ├── libqmacheif.dylib
│ ├── libqmacjp2.dylib
│ ├── libqsvg.dylib
│ ├── libqtga.dylib
│ ├── libqtiff.dylib
│ ├── libqwbmp.dylib
│ └── libqwebp.dylib
├── mediaservice
│ ├── libqavfcamera.dylib
│ ├── libqavfmediaplayer.dylib
│ └── libqtmedia_audioengine.dylib
├── platforminputcontexts
│ └── libqtvirtualkeyboardplugin.dylib
├── platforms
│ ├── libqcocoa.dylib
│ ├── libqminimal.dylib
│ ├── libqoffscreen.dylib
│ └── libqwebgl.dylib
├── platformthemes
│ └── libqxdgdesktopportal.dylib
├── playlistformats
│ └── libqtmultimedia_m3u.dylib
├── position
│ ├── libqtposition_cl.dylib
│ ├── libqtposition_positionpoll.dylib
│ └── libqtposition_serialnmea.dylib
├── printsupport
│ └── libcocoaprintersupport.dylib
├── qmltooling
│ ├── libqmldbg_debugger.dylib
│ ├── libqmldbg_inspector.dylib
│ ├── libqmldbg_local.dylib
│ ├── libqmldbg_messages.dylib
│ ├── libqmldbg_native.dylib
│ ├── libqmldbg_nativedebugger.dylib
│ ├── libqmldbg_preview.dylib
│ ├── libqmldbg_profiler.dylib
│ ├── libqmldbg_quickprofiler.dylib
│ ├── libqmldbg_server.dylib
│ └── libqmldbg_tcp.dylib
├── renderers
│ └── libopenglrenderer.dylib
├── renderplugins
│ └── libscene2d.dylib
├── sceneparsers
│ ├── libgltfsceneexport.dylib
│ └── libgltfsceneimport.dylib
├── sensorgestures
│ ├── libqtsensorgestures_plugin.dylib
│ └── libqtsensorgestures_shakeplugin.dylib
├── sensors
│ ├── libqtsensors_generic.dylib
│ └── libqtsensors_ios.dylib
├── sqldrivers
│ └── libqsqlite.dylib
├── styles
│ └── libqmacstyle.dylib
├── texttospeech
│ └── libqtexttospeech_speechosx.dylib
├── virtualkeyboard
│ ├── libqtvirtualkeyboard_hangul.dylib
│ ├── libqtvirtualkeyboard_openwnn.dylib
│ ├── libqtvirtualkeyboard_pinyin.dylib
│ ├── libqtvirtualkeyboard_tcime.dylib
│ └── libqtvirtualkeyboard_thai.dylib
└── webview
└── libqtwebview_darwin.dylib
Still works here, so 156cf62b8a
This does not work for me (MSVC 2019). I get these warnings and errors:
4>D:\FreeCAD-git\src\Tools\plugins\widget\customwidgets.cpp(143,54): warning C4996: 'QString::null': use QString()
4>D:\FreeCAD-git\src\Tools\plugins\widget\customwidgets.cpp(156,50): warning C4996: 'QFontMetrics::width': Use QFontMetrics::horizontalAdvance
4>D:\FreeCAD-git\src\Tools\plugins\widget\customwidgets.cpp(219,37): warning C4996: 'QFontMetrics::width': Use QFontMetrics::horizontalAdvance
4>D:\FreeCAD-git\src\Tools\plugins\widget\customwidgets.cpp(220,37): warning C4996: 'QFontMetrics::width': Use QFontMetrics::horizontalAdvance
4>D:\FreeCAD-git\src\Tools\plugins\widget\customwidgets.cpp(1394,9): warning C4996: 'QDrag::start': Use QDrag::exec() instead
4>D:\FreeCAD-git\src\Tools\plugins\widget\customwidgets.h(161,14): warning C4996: 'QFlags<Qt::WindowType>::QFlags': Use default constructor instead (compiling source file D:\FreeCAD-git\src\Tools\plugins\widget\plugin.cpp)
4> Creating library D:/FreeCAD-build/src/Tools/plugins/widget/Release/FreeCAD_widgets.lib and object D:/FreeCAD-build/src/Tools/plugins/widget/Release/FreeCAD_widgets.exp
4>customwidgets.obj : error LNK2019: unresolved external symbol "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) referenced in function "public: __cdecl Gui::ActionSelector::ActionSelector(class QWidget *)" (??0ActionSelector@Gui@@QEAA@PEAVQWidget@@@Z)
4>plugin.obj : error LNK2001: unresolved external symbol "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z)
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z)
4>customwidgets.obj : error LNK2019: unresolved external symbol "void __cdecl operator delete(void *,unsigned __int64)" (??3@YAXPEAX_K@Z) referenced in function "int `public: __cdecl Gui::ActionSelector::ActionSelector(class QWidget *)'::`1'::dtor$1" (?dtor$1@?0???0ActionSelector@Gui@@QEAA@PEAVQWidget@@@Z@4HA)
4>plugin.obj : error LNK2001: unresolved external symbol "void __cdecl operator delete(void *,unsigned __int64)" (??3@YAXPEAX_K@Z)
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol "void __cdecl operator delete(void *,unsigned __int64)" (??3@YAXPEAX_K@Z)
4>customwidgets.obj : error LNK2001: unresolved external symbol __std_terminate
4>customwidgets.obj : error LNK2019: unresolved external symbol _CxxThrowException referenced in function __catch$?append@?$QList@VQString@@@@QEAAXAEBVQString@@@Z$0
4>plugin.obj : error LNK2001: unresolved external symbol _CxxThrowException
4>customwidgets.obj : error LNK2001: unresolved external symbol __CxxFrameHandler4
4>plugin.obj : error LNK2001: unresolved external symbol __CxxFrameHandler4
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol __CxxFrameHandler4
4>customwidgets.obj : error LNK2001: unresolved external symbol __GSHandlerCheck
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol __GSHandlerCheck
4>customwidgets.obj : error LNK2001: unresolved external symbol __GSHandlerCheck_EH4
4>customwidgets.obj : error LNK2019: unresolved external symbol __security_check_cookie referenced in function "public: class QString __cdecl QString::arg<class QString &,class QString const &>(class QString &,class QString const &)const " (??$arg@AEAVQString@@AEBV1@@QString@@QEBA?AV0@AEAV0@AEBV0@@Z)
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol __security_check_cookie
4>customwidgets.obj : error LNK2019: unresolved external symbol memcpy referenced in function "private: void __cdecl QList<class QListWidgetItem *>::node_copy(struct QList<class QListWidgetItem *>::Node *,struct QList<class QListWidgetItem *>::Node *,struct QList<class QListWidgetItem *>::Node *)" (?node_copy@?$QList@PEAVQListWidgetItem@@@@AEAAXPEAUNode@1@00@Z)
4>plugin.obj : error LNK2001: unresolved external symbol memcpy
4>customwidgets.obj : error LNK2001: unresolved external symbol "const type_info::`vftable'" (??_7type_info@@6B@)
4>plugin.obj : error LNK2001: unresolved external symbol "const type_info::`vftable'" (??_7type_info@@6B@)
4>customwidgets.obj : error LNK2019: unresolved external symbol __security_cookie referenced in function "public: class QString __cdecl QString::arg<class QString &,class QString const &>(class QString &,class QString const &)const " (??$arg@AEAVQString@@AEBV1@@QString@@QEBA?AV0@AEAV0@AEBV0@@Z)
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol __security_cookie
4>customwidgets.obj : error LNK2001: unresolved external symbol _fltused
4>mocs_compilation_Release.obj : error LNK2001: unresolved external symbol _fltused
4>plugin.obj : error LNK2001: unresolved external symbol _purecall
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol "void __cdecl operator delete(void *)" (??3@YAXPEAX@Z) referenced in function "void __cdecl `qt_plugin_instance'::`2'::`dynamic atexit destructor for '_instance''(void)" (??__F_instance@?1??qt_plugin_instance@@9@YAXXZ)
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol atexit referenced in function qt_plugin_instance
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol _Init_thread_header referenced in function qt_plugin_instance
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol _Init_thread_footer referenced in function qt_plugin_instance
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol strcmp referenced in function "public: virtual void * __cdecl CustomWidgetPlugin::qt_metacast(char const *)" (?qt_metacast@CustomWidgetPlugin@@UEAAPEAXPEBD@Z)
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol _Init_thread_epoch referenced in function qt_plugin_instance
4>mocs_compilation_Release.obj : error LNK2019: unresolved external symbol _tls_index referenced in function qt_plugin_instance
4>LINK : error LNK2001: unresolved external symbol _DllMainCRTStartup
4>D:\FreeCAD-build\src\Tools\plugins\widget\Release\FreeCAD_widgets.dll : fatal error LNK1120: 21 unresolved externals