我正在开发一个依赖于 wxWidgets 的 C++ 项目。
我可以使用 wxWidgets 文档中的以下 Makefile 来编译应用程序:
PROGRAM = App
OBJECTS := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
# implementation
.SUFFIXES: .o .cpp
.cpp.o :
$(CXX) -O2 -g -c `wx-config --cxxflags` -o $@ $<
all: $(PROGRAM)
$(PROGRAM): $(OBJECTS)
$(CXX) -O2 -g -o $(PROGRAM) $(OBJECTS) `wx-config --libs`
clean:
rm -f *.o $(PROGRAM)
但是,我决定尝试 bazel 作为我的构建系统。
我在运行 `bazel build //src:app --verbose_failures:
时收到以下错误In file included from external/wx/wx/defs.h:45,
from external/wx/wx/memory.h:14,
from external/wx/wx/object.h:19,
from external/wx/wx/utils.h:18,
from external/wx/wx/thrimpl.cpp:344:
external/wx/wx/platform.h:159:10: fatal error: wx/setup.h: No such file or directory
159 | #include "wx/setup.h"
| ^~~~~~~~~~~~
这是我的
WORKSPACE
文件:
new_local_repository(
name="wx",
path="/usr/include/wx-3.2",
build_file_content = """
package(default_visibility = ["//visibility:public"])
cc_library(
name = "headers",
hdrs = glob(["**/*.h"]),
srcs = glob(["**/*.cpp"]),
includes = ["/usr/include/wx-3.2"],
)
"""
)
new_local_repository(
name="gtk-unicode",
path="/usr/lib/wx/include/gtk3-unicode-3.2",
build_file_content = """
package(default_visibility = ["//visibility:public"])
cc_library(
name = "headers",
hdrs = glob(["**/*.h"])
)
"""
)
src/BUILD
:
cc_library(
name="agent",
srcs=["Agent.cpp"],
hdrs=["Agent.h"],
deps=[":game"]
)
cc_library(
name="game",
srcs=["Game.cpp"],
hdrs=["Game.h"],
)
cc_binary(
name="app",
srcs=["App.cpp"],
deps=[":agent", ":game", "@wx//:headers", "@gtk-unicode//:headers"],
copts=[
"-Iexternal/wx",
"-Iexternal/gtk-unicode",
"-DWXUSINGDLL",
"-D__WXGTK3__",
"-D__WXGTK__",
"-pthread",
"-lwx_gtk3u_xrc-3.2",
"-lwx_gtk3u_html-3.2",
"-lwx_gtk3u_qa-3.2",
"-lwx_gtk3u_core-3.2",
"-lwx_baseu_xml-3.2",
"-lwx_baseu_net-3.2",
"-lwx_baseu-3.2"
]
)
我不知道是否有一些优雅的方法告诉 bazel 自己执行
wx-config
,但在最坏的情况下,你可以将 wx-config --cxxflags
的输出复制并粘贴到 includes
赋值中( --libs
也是一样)。
回答这个问题的困难在于,wxwidgets 提供了一种开箱即用的编译和链接方式,这违背了 Bazel 的理念。根据您所在的平台,步骤有很大不同。本质上,当您安装 wxwidgets 时,无论是从源代码还是从预制操作系统包进行编译,它都会附带 wx-config 实用程序,该实用程序将通过 shell 命令生成编译器工作所需的标志。
然而,在 Bazel 中,您需要向 Bazel 本身声明源、标头和定义,然后它会推导出编译器标志。为了使其工作,您需要推断 wx-config 生成的标志在您的平台中意味着什么,然后将它们写入 Bazel 中。这是我在 Ubuntu 22.04 中对 wxwidgets 包所做的操作。
wx-config --cxxflags 的输出是:
-I/usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.0 -I/usr/include/wx-3.0 -D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXGTK__ -pthread
请注意,有两个包含文件夹、三个定义和 -pthread 编译器选项。对于 wx-config --libs 我们有:
-L/usr/lib/x86_64-linux-gnu -pthread -lwx_gtk3u_xrc-3.0 -lwx_gtk3u_html-3.0 -lwx_gtk3u_qa-3.0 -lwx_gtk3u_adv-3.0 -lwx_gtk3u_core-3.0 -lwx_baseu_xml-3.0 -lwx_baseu_net-3.0 -lwx_baseu-3.0
这里我们只有一个库文件夹,Linux 中的标志 -lfoo 会转换为 libfoo.so。
无论如何,当我们将其转换为 Bazel 时,我们需要将以下存储库添加到 WORKSPACE 文件中:
new_local_repository(
name = "wxheaders",
build_file = "wxheaders.BUILD",
path = "/usr/include/wx-3.0",
)
new_local_repository(
name = "wxwidgets",
build_file = "wxwidgets.BUILD",
path = "/usr/lib/x86_64-linux-gnu",
)
对于 wxheaders.BUILD 文件,将您可以在文件夹中找到的所有标头放入:
cc_library(
name = "wxheaders",
hdrs = glob(["**"]),
includes = ["."],
visibility = ["//visibility:public"],
)
对于wxwidgets.BUILD文件,我们有头文件和共享库,我们可以使用
cc_library(
name = "wxwidgets",
srcs = [
"libwx_gtk3u_xrc-3.0.so",
"libwx_gtk3u_html-3.0.so",
"libwx_gtk3u_qa-3.0.so",
"libwx_gtk3u_adv-3.0.so",
"libwx_gtk3u_core-3.0.so",
"libwx_baseu_xml-3.0.so",
"libwx_baseu_net-3.0.so",
"libwx_baseu-3.0.so",
],
hdrs = glob(["wx/include/gtk3-unicode-3.0/**"]),
includes = [
"wx/include/gtk3-unicode-3.0",
],
defines = [
"_FILE_OFFSET_BITS=64",
"WXUSINGDLL",
"__WXGTK__",
],
linkopts = ["-pthread"],
deps = [
"@wxheaders//:wxheaders",
],
visibility = ["//visibility:public"],
)
最后,当您要构建二进制文件时,请在 copts 中添加缺少的 -pthread (我们无法将其添加到依赖项中,因为它不会传播)。 BUILD 文件应如下所示:
cc_binary(
name = "main",
srcs = ["main.cpp"],
copts = [
"-pthread"
],
deps = [
"@wxwidgets//:wxwidgets",
],
)
另一种选择是在 .bazelrc 文件中添加 -pthread copt(如果您同意在整个项目中使用它)。有几种方法可以解决这个问题。
如前所述,具体步骤很大程度上取决于您的操作系统以及wxwidgets的安装方式,但我希望这个示例可以帮助您入门。