3

I tried to build and run a Qt5 (5.15.2) application on macOS (10.15.7) using Bazel 5.0.0. Unfortunately, I run into some problems. The building part seems to work, but not the run part.

I installed Qt5 on my machine using Homebrew:

brew install qt@5
brew link qt@5

I adapted https://github.com/justbuchanan/bazel_rules_qt/ to my needs. See this PR. When I try to run:

bazel run --cxxopt=-std=c++17 //tests/qt_resource:main

I receive the runtime error:

dyld: Symbol not found: __ZN10QByteArray6_emptyE

Steps to reproduce the issue:

# brew install bazel # Install Bazel
# brew install qt@5  # Install Qt5
git clone https://github.com/Vertexwahn/bazel_rules_qt.git
cd bazel_rules_qt
git checkout add-macos-support
bazel build --cxxopt=-std=c++17 //... # should work
bazel run --cxxopt=-std=c++17 //tests/qt_resource:main # should give you the error message

Nevertheless, building everything using bazel build --cxxopt=-std=c++17 //... seems to work. I am not 100% sure if the link options -F/usr/local/opt/qt5/Frameworks and -framework QtCore, etc. are correct. Maybe someone can confirm this.

Did I use the correct link options?

For me, it is a bit unclear what dependencies the main binary expects. I tried to copy QtCore.framework to the location of the main binary manually but this does not change the error message.

What files does the main binary expect?

If I try to run macdeployqt on my main binary I get also some errors. I do within my workspace root dir a cd bazel-bin/tests/qt_resource and run then /usr/local/opt/qt5/bin/macdeployqt main:

ERROR: Could not find bundle binary for "main"
ERROR: "error: /Library/Developer/CommandLineTools/usr/bin/otool-classic: can't open file:  (No such file or directory)\n"
ERROR: "error: /Library/Developer/CommandLineTools/usr/bin/otool-classic: can't open file:  (No such file or directory)\n"
ERROR: "error: /Library/Developer/CommandLineTools/usr/bin/otool-classic: can't open file:  (No such file or directory)\n"
WARNING:
WARNING: Could not find any external Qt frameworks to deploy in "main"
WARNING: Perhaps macdeployqt was already used on "main" ?
WARNING: If so, you will need to rebuild "main" before trying again.
ERROR: Could not find bundle binary for "main"
ERROR: "error: /Library/Developer/CommandLineTools/usr/bin/strip: can't open file:  (No such file or directory)\n"
ERROR: ""

My hope was that macdeployqt would collect all needed resources for me. Any idea why this is not working?

How can macdeployqt be used to collect all needed dependencies for the main binary?

If I convert my main to an app via lipo -create -output universall_app main and do then a /usr/local/opt/qt5/bin/macdeployqt universall_app I get the same error message.

The CMake approach

To make sure that there is no general problem with my system setup I tried to use CMake to build a Qt5 application:

git clone https://github.com/euler0/mini-cmake-qt.git
cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 .
make -j

This produces an example.app. With a double click on this application bundle, the application can be started. This worked on my system.

Future directions

It seems that rules_apple can be used to create an application bundle. I am not sure if I need to transform my Qt application binary to an app bundle to be able to execute it. One could use --sandbox_debugto identify what Bazel is doing and dtruss for the CMake version to compare the differences. I am currently not sure what trying to do next and hope for an easy solution. I am also fine with a Qt6 solution.

Update: Alternative Answer

It would also be helpful if someone can point out how to build a minimal Qt application using make only on macOS and a brew installed Qt5 or tell me what the linker and compiler options must look like.

Vertexwahn
  • 7,709
  • 6
  • 64
  • 90
  • I dont know how you are doing that and what you mean ( sorry I have not MacOS ) but you can see gRPC , it is good example for you(maybe it be helpful): https://github.com/grpc/grpc/blob/master/BUILDING.md – H.M Feb 12 '22 at 17:34
  • Would it be an alternative to not use bazel? – cascading-jox Feb 14 '22 at 06:58
  • @cascading-jox See updated question (section "Update: Alternative Answer") – Vertexwahn Feb 14 '22 at 22:04

1 Answers1

2

I followed your steps with Mac OSX 10.15.7, Qt (installed by homebrew) 5.15.1 and both bazel 4.2.2-homebrew and 5.0.0-homebrew and initially I could not build the project from git:

* 3fe5f6c - (4 weeks ago) Add macOS support — Vertexwahn (HEAD -> add-macos-support, origin/add-macos-support)

This is the result that I get when building:

 % bazel build --cxxopt=-std=c++17  //...
 DEBUG: /private/var/tmp/_bazel_home/761aafaa2237a9607dd915f1f52bca3e/external/com_justbuchanan_rules_qt/qt_configure.bzl:43:14: Installation available on the default path:  /usr/local/opt/qt5
 INFO: Analyzed 14 targets (0 packages loaded, 0 targets configured).
 INFO: Found 14 targets...
 ERROR: /Users/home/Git/my_repo/bazel_rules_qt/tests/qt_qml/BUILD:4:10: Compiling tests/qt_qml/main.cc failed: (Aborted): wrapped_clang failed: error executing command external/local_config_cc/wrapped_clang '-D_FORTIFY_SOURCE=1' -fstack-protector -fcolor-diagnostics -Wall -Wthread-safety -Wself-assign -fno-omit-frame-pointer -O0 -DDEBUG '-std=c++11' ... (remaining 38 argument(s) skipped)

 Use --sandbox_debug to see verbose messages from the sandbox
 tests/qt_qml/main.cc:1:10: fatal error: 'QtQml/QQmlApplicationEngine' file not found
 #include <QtQml/QQmlApplicationEngine>
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1 error generated.
 Error in child process '/usr/bin/xcrun'. 1
 INFO: Elapsed time: 0,594s, Critical Path: 0,32s
 INFO: 3 processes: 3 internal.
 FAILED: Build did NOT complete successfully

After playing around with headers and include paths in qt.BUILD:

 diff --git a/qt.BUILD b/qt.BUILD
 index 517c8db..8f110b5 100644
 --- a/qt.BUILD
 +++ b/qt.BUILD
 @@ -28,11 +28,12 @@ QT_LIBRARIES = [
      cc_library(
          name = "qt_%s_osx" % name,
          # When being on Windows this glob will be empty
 -        hdrs = glob(["%s/**" % include_folder], allow_empty = True),
 +        hdrs = glob(["include/%s/**" % include_folder], allow_empty = True),
          includes = ["."],
          linkopts = ["-F/usr/local/opt/qt5/lib"] + [
              "-framework %s" % library_name.replace("5", "") # macOS qt libs do not contain a 5 - e.g. instead of Qt5Core the lib is called QtCore
              ],
 +        strip_include_prefix= "include"
          # Available from Bazel 4.0.0
          # target_compatible_with = ["@platforms//os:osx"],
      )

I could build and run the project:

 % bazel build --cxxopt=-std=c++17  //...
 DEBUG: /private/var/tmp/_bazel_home/761aafaa2237a9607dd915f1f52bca3e/external/com_justbuchanan_rules_qt/qt_configure.bzl:43:14: Installation available on the default path:  /usr/local/opt/qt5
 INFO: Analyzed 14 targets (1 packages loaded, 7422 targets configured).
 INFO: Found 14 targets...
 INFO: Elapsed time: 11,761s, Critical Path: 7,23s
 INFO: 3 processes: 1 internal, 2 darwin-sandbox.
 INFO: Build completed successfully, 3 total actions
 % bazel run --cxxopt=-std=c++17 //tests/qt_resource:main
 DEBUG: /private/var/tmp/_bazel_home/761aafaa2237a9607dd915f1f52bca3e/external/com_justbuchanan_rules_qt/qt_configure.bzl:43:14: Installation available on the default path:  /usr/local/opt/qt5
 INFO: Analyzed target //tests/qt_resource:main (0 packages loaded, 0 targets configured).
 INFO: Found 1 target...
 Target //tests/qt_resource:main up-to-date:
 bazel-bin/tests/qt_resource/main
 INFO: Elapsed time: 3,657s, Critical Path: 0,00s
 INFO: 1 process: 1 internal.
 INFO: Build completed successfully, 1 total action
 INFO: Build completed successfully, 1 total action
 opened resource file
 file1

Related to your question whether the linker options are correct -F/usr/local/opt/qt5/Frameworks -framework QtCore

Yes they are correct, you could alternatively use -F/usr/local/opt/qt5/lib (as you are already using in qt.BUILD) as all the files under the Frameworks folder are links to the lib folder.

With macdeployqt and lipo I get the same results as in the OP even after the test is running successfully.

pero_hero
  • 2,881
  • 3
  • 10
  • 24
  • Your solution works! Great! Nevertheless, currently much more is included than necessary which leads to symlinking of many virtual headers and leads elongated compile times.. Would be happy if this could be optimized a bit more. – Vertexwahn Feb 16 '22 at 16:42
  • okay could fix it myself `hdrs = glob(["%s/**" % include_folder], allow_empty = True), includes = ["."],` – Vertexwahn Feb 16 '22 at 16:49
  • 1
    I added an optimisation of the included folders. – pero_hero Feb 16 '22 at 17:15