sassanh / qnvim

Neovim backend for Qt Creator
MIT License
136 stars 8 forks source link

Use CMake to build plugin + fetch dependencies automatically #34

Closed gikari closed 2 years ago

gikari commented 2 years ago

Summary

This change ports the QMake build to CMake - a recommended way to build plugins according to the Qt Documentation: https://doc.qt.io/qtcreator-extending/first-plugin.html#cmake-project

This also adds a number of useful features, for example, an ability to fetch neovim-qt and qtcreator automatically.

Neovim-qt is downloaded and built with the Message Pack using FetchContent CMake feature. In case of QtCreator only the precompiled binaries are downloaded to save time.

Test Plan

  1. Ensure Neovim is installed and in the PATH
  2. Open the CMake project in QtCreator (any version).
  3. Once successfully configured, set in run configuration the following:
    • Executable: %{buildDir}\_deps\qtcreator-src\bin\qtcreator.exe
    • Command line arguments: -pluginpath %{buildDir}\lib\qtcreator\plugins
      1. Build the project and run. This will launch a Qt Creator of compatible version.
      2. Open a file and test that the plugin is working. Make sure you have FakeVim disabled.

Configurations tested:

CC #32

sassanh commented 2 years ago

Thanks! I'm getting errors like these in macOS:

.../qnvim/src/qnvimplugin.cpp:165:31: error: no member named 'hasBlockSelection' in 'TextEditor::TextEditorWidget'
    auto cursor = textEditor->hasBlockSelection() ? textEditor->blockSelection() : textEditor->textCursor();
                  ~~~~~~~~~~  ^
.../qnvim/src/qnvimplugin.cpp:165:65: error: no member named 'blockSelection' in 'TextEditor::TextEditorWidget'
    auto cursor = textEditor->hasBlockSelection() ? textEditor->blockSelection() : textEditor->textCursor();
                                                    ~~~~~~~~~~  ^
.../qnvim/src/qnvimplugin.cpp:172:21: error: no member named 'hasBlockSelection' in 'TextEditor::TextEditorWidget'
    if (textEditor->hasBlockSelection()) {
        ~~~~~~~~~~  ^
.../qnvim/src/qnvimplugin.cpp:289:21: error: no member named 'setBlockSelection' in 'TextEditor::TextEditorWidget'
        textEditor->setBlockSelection(cursor);
        ~~~~~~~~~~  ^
.../qnvim/src/qnvimplugin.cpp:810:69: error: no viable conversion from 'QString' to 'const Utils::FilePath'
                    if (mEditors[buffer]->document()->save(nullptr, filename)) {
                                                                    ^~~~~~~~
.../Qt/Qt Creator.app/Contents/Resources/Headers/qtcreator/src/libs/utils/filepath.h:66:30: note: candidate constructor (t
he implicit copy constructor) not viable: no known conversion from 'QString' to 'const Utils::FilePath &' for 1st argument
class QTCREATOR_UTILS_EXPORT FilePath

Do you know anything about it?

gikari commented 2 years ago

I've got similar errors when building against Qt Creator of later versions because of changed APIs. Perhaps CMake is linking to incorrect version of Qt Creator libs (the ones installed in the system, not the fetched ones).

I took a look at the contetns of archive that is downloaded for macOS and it's quite different layout from Windows and Linux archives (CMAKE_PREFIX_PATH expects (at least on WIndows and Linux) the path to have lib and include directories, but macOS archive have additional QtCreator.app/Contents/{Resources,Frameworks} prefixes).

It seems like for macOS we need to set CMAKE_APPBUNDLE_PATH and CMAKE_FRAMEWORK_PATH in addition to CMAKE_PREFIX_PATH.

sassanh commented 2 years ago

I'm a bit confused, are you using an older version of QtCreator compiled with Qt 5 to be able to compile and use this plugin? Because now I remember this plugin is not compatible with Qt Creator built with Qt 6, right?

If that's the case I need to install an older version of Qt Creator, do you know what's the latest version using Qt 5?

gikari commented 2 years ago

You don't have to install Qt Creator with this patch - it is downloaded for you with the specific hardcoded version. In this case it's 4.15.2 (It is old, but requires small amount of fixes in plugin source code). After it is downloaded, the plugin is built against it. After successful but you can launch an instance of it with the enabled plugin to test it.

But in your case (on macOS) something went wrong and now the plugin build system tries to use some other Qt Creator, not the automatically downloaded one, hence the errors above.

sassanh commented 2 years ago

I see, that should be it then. I'm getting this error (even with your latest commit):

CMake Error at CMakeLists.txt:29 (find_package):
  By not providing "FindQtCreator.cmake" in CMAKE_MODULE_PATH this project
  has asked CMake to find a package configuration file provided by
  "QtCreator", but CMake did not find one.

  Could not find a package configuration file provided by "QtCreator" with
  any of the following names:

    QtCreatorConfig.cmake
    qtcreator-config.cmake

  Add the installation prefix of "QtCreator" to CMAKE_PREFIX_PATH or set
  "QtCreator_DIR" to a directory containing one of the above files.  If
  "QtCreator" provides a separate development package or SDK, be sure it has
  been installed.

I was setting QtCreator_DIR to a Qt Creator 6 directory as suggested in the error message.

gikari commented 2 years ago

You should not need to add it. Could you try a clean build with the commit I just added?

sassanh commented 2 years ago
FetchContent_Declare(
  qtcreator
  URL "${QTC_URL}"
  URL_HASH MD5=${QTC_MD5}
)

This is extracting qtcreator-macOS-1029797214.7z directly into build/_deps/qtcreator-src (creating build/_deps/qtcreator-src/Contents) while this:

  file(ARCHIVE_EXTRACT INPUT "${PROJECT_BINARY_DIR}/downloads/qtc_dev.7z" DESTINATION "${qtcreator_SOURCE_DIR}")

is extracting qtcreator-Linux-1029797214_dev.7z into build/_deps/qtcreator-src/Qt Creator.app, the result is this:

$ ls build/_deps/qtcreator-src/
Contents/       Qt Creator.app/

Either Contents/ should be inside Qt Creator.app/ or the contents of Qt Creator.app/ should be directly extracted next to Contents/ (I prefer the first one, cause I think it will make things easier with CMAKE_APPBUNDLE_PATH)

gikari commented 2 years ago

I fixed the directory structure bug, so you are welcome to test it.

sassanh commented 2 years ago

Thanks! Now I need to apply this diff:

diff --git a/cmake/FetchQtCreator.cmake b/cmake/FetchQtCreator.cmake
index 7a6ffae..9939cf7 100644
--- a/cmake/FetchQtCreator.cmake
+++ b/cmake/FetchQtCreator.cmake
@@ -51,7 +51,11 @@ if(NOT qtcreator_POPULATED)
   # Add dev files into the same directory
   file(DOWNLOAD "${QTC_DEV_URL}" "${qtcreator_SOURCE_DIR}/qtc_dev.7z" EXPECTED_MD5 ${QTC_DEV_MD5})
   file(ARCHIVE_EXTRACT INPUT "${qtcreator_SOURCE_DIR}/qtc_dev.7z" DESTINATION "${qtcreator_BINARY_DIR}")
+endif()

-  # Let the CMake Find scripts find Qt Creator files
+# Let the CMake Find scripts find Qt Creator files
+if(APPLE) # macOS
+  list(APPEND CMAKE_PREFIX_PATH "${qtcreator_BINARY_DIR}/Qt Creator.app/Contents/Resources/lib/cmake/QtCreator")
+else()
   list(APPEND CMAKE_PREFIX_PATH "${qtcreator_BINARY_DIR}")
 endif()

so that cmake finds Qt Creator.

And I'm getting this error:

CMake Error at build/_deps/qtcreator-build/Qt Creator.app/Contents/Resources/lib/cmake/QtCreator/QtCreatorAPIInternal.cmake:302 (target_link_libraries)
:
  Target "QNVim" links to:

    Qt6::Widgets

  but the target was not found.  Possible reasons include:

    * There is a typo in the target name.
    * A find_package call is missing for an IMPORTED target.
    * An ALIAS target is missing.

Call Stack (most recent call first):
  build/_deps/qtcreator-build/Qt Creator.app/Contents/Resources/lib/cmake/QtCreator/QtCreatorAPIInternal.cmake:475 (add_qtc_depends)
  build/_deps/qtcreator-build/Qt Creator.app/Contents/Resources/lib/cmake/QtCreator/QtCreatorAPI.cmake:460 (extend_qtc_target)
  CMakeLists.txt:33 (add_qtc_plugin)
sassanh commented 2 years ago

Considering we are building for a Qt 5 version of Qt Creator, do we need Qt 6 in the build process? I was able to build the plugin by applying this diff (I don't know much about cmake, please check it):

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b51aa78..9ba1ba7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,8 +27,7 @@ if (MSVC)
 endif()

 find_package(QtCreator REQUIRED COMPONENTS Core)
-find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network REQUIRED)
-set(QtX Qt${QT_VERSION_MAJOR})
+find_package(Qt5 COMPONENTS Widgets Network REQUIRED)

 add_qtc_plugin(QNVim
   PLUGIN_DEPENDS
@@ -36,7 +35,7 @@ add_qtc_plugin(QNVim
     QtCreator::TextEditor
     QtCreator::ProjectExplorer
   DEPENDS
-    ${QtX}::Widgets
+    Qt5::Widgets
     QtCreator::ExtensionSystem
     QtCreator::Utils
     neovim-qt

But now Qt Creator (the one in build/_deps/qtcreator-build) crashes when I add the plugin and restart it. doesn't show any informative error:

image
gikari commented 2 years ago

No we don't need Qt6 for now. Indeed we can remove the Qt6 from dependencies.

As for crash: this is strange. Did you try to run it with the debugger?

gikari commented 2 years ago

I applied a Qt version patch and tried to fix the find_package for macOS by removing the space in the bundle name. I'm still not sure if it will work, since CMake docs do not list the path you added explicitly in their locations for search in macOS.

Could you test if it works? If not, maybe the subdirectories of a bundle could be added to CMAKE_PREFIX_PATH.

sassanh commented 2 years ago

Unfortunately it didn't work, still getting this error:

CMake Error at CMakeLists.txt:29 (find_package):
  By not providing "FindQtCreator.cmake" in CMAKE_MODULE_PATH this project
  has asked CMake to find a package configuration file provided by
  "QtCreator", but CMake did not find one.

  Could not find a package configuration file provided by "QtCreator" with
  any of the following names:

    QtCreatorConfig.cmake
    qtcreator-config.cmake

  Add the installation prefix of "QtCreator" to CMAKE_PREFIX_PATH or set
  "QtCreator_DIR" to a directory containing one of the above files.  If
  "QtCreator" provides a separate development package or SDK, be sure it has
  been installed.

It works by adding the subdirectories of the bundle to CMAKE_PREFIX_PATH, you can see it in the diff snippet I provided here

sassanh commented 2 years ago

Latest commit is good. I try to find some time to see why it is crashing in macOS.

sassanh commented 2 years ago

The problem was a misconfiguration on my machine living from old versions. All is good now, thanks!