交叉编译 Ubuntu-Win7 使用自定义 Makefile 而不是 qmake
Cross-compilation Ubuntu-Win7 using a custom Makefile instead of qmake
我有一个项目使用 Qt4,没有额外的库和 QtSql(用于使用 SQLLite 数据库),我想为 x86_64 Windows 7 机器交叉编译它。这是我总结的 makefile(除了 main.cpp,它只使用 .hpp 文件,因为我使用了很多模板):
CXX=g++-4.8
CXXFLAGS=-std=c++11 -pedantic -Wall -pedantic-errors -Wextra
IPATH=-I/usr/include/qt4/ -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtSql
LDFLAGS=-lQtGui -lQtSql -lQtCore
OBJS=main.o
HEADERS=mymoc1.hpp mymoc2.hpp other-headers
all: myexec
myexec: $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $@ $(LDFLAGS)
main.o: main.cpp $(HEADERS)
$(CXX) -c $(CXXFLAGS) $< -o $@ $(IPATH)
mymoc1.hpp: the-header-needing-moc.hpp
moc $< -o $@
mymoc2.hpp: other-header-needing-moc.hpp
moc $< -o $@
我要学习下一个教程:http://mxe.cc/#tutorial
假设我已经成功完成了前四个步骤,我的疑问来自于在 5c 和 5d 步骤之间进行选择。在我的情况下我应该使用什么以及如何使用?像 QtSql 这样的依赖会发生什么?还有 moc?
此外,我是否应该按照教程中的说明定义 LD、AR 或 PKG_CONFIG 变量?我没有在原始 makefile 中指定链接器或汇编器。如果我应该,为什么?
编辑 我读过 here mingw
在使用模板时遇到问题,我在我的项目中深入使用了它们。由于 MXE 在内部使用 mingw
,我是否应该考虑其他替代方案(例如直接在 Windows 中构建)而不是使用 MXE?
我将在这里 post 我自己的答案,但充满了细节,因为我很迷茫,也许其他用户也处于类似情况。
I am going to follow the next tutorial: http://mxe.cc/#tutorial Supposing I've complete successfully the first fourth steps, my doubt comes from choosing between 5c and 5d steps. What shall I use and how in my case?
是的,您(我确实是在回答我自己的问题)可以使用 Makefile 交叉编译静态链接的 Qt 项目。问题是,由于 Qt 是静态链接的,任何其他 Qt 依赖项也必须是静态链接的,这会创建一个潜在的长字符串库依赖项以添加到您的 Makefile 中(并且您还需要知道要传递的正确选项到链接器)。问题是这些选项或库中的一些在 windows-specific 旁边,因此,如果您以前从未为 Windows 编译过程序,那么您很难知道它们是什么以及它们的用途.
出于这个原因,您可以做的最好的事情就是编写自己的 .pro
文件来创建一个带有 qmake
的工作 Makefile。在这一点上,如果你仍然想制作你的自定义 Makefile,你可以执行 qmake
生成的 makefile
并查看执行的命令,复制回来并在你的自定义 Makefile 中进行试验。
无论如何,我会 post 我到达的最远的地方 makefile
(稍后在这个 post 我将展示我的工作 *.pro
文件的样子)。它编译成功,但是在链接时崩溃了,因为有很多未解决的依赖关系我无法按照上面的方法修复(我的 mxe 安装在 `/usr/local/mxe):
ifndef CROSS
CROSS=x86_64
endif
CROSS_ID=$(CROSS)-w64-mingw32.static
MXE_BASE=/usr/local/mxe/usr
MXE_USR=$(MXE_BASE)/$(CROSS_ID)
MXE_INCL=$(MXE_USR)/include
MXE_QTINCL=$(MXE_USR)/qt/include
MXE_LIB=$(MXE_USR)/lib
MXE_QTLIB=$(MXE_USR)/qt/lib
LDIFLAGS=-I$(MXE_INCL) -I$(MXE_QTINCL)/QtCore -I$(MXE_QTINCL)/QtGui -I$(MXE_QTINCL)/QtSql
LDLFLAGS=-L$(MXE_LIB) -L$(MXE_QTLIB)
LDLIBS=-Wl,-Bstatic -lwinmm -loleut32 -lQtGui -lQtSql -lQtCore
CXX=$(MXE_PATH)/bin/$(CROSS_ID)-g++
CXXFLAGS=-std=c++11 -pedantic -pedantic-errors -Wall
OBJS=main.o
MOC_HEADERS=mymoc1.hpp mymoc2.hpp
HEADERS=$(MOC_HEADERS) myheaders
APP=myapp.exe
all: $(APP)
$(APP): $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $@ $(LDLFLAGS) $(LDLIBS)
main.o: main.cpp $(HEADERS)
$(CXX) $(CXXFLAGS) $< -o $@ $(LDIFLAGS)
mymoc1: header1.hpp
moc $< -o $@
mymoc2: header2.hpp
moc $< -o $@
# Thee ways of call it:
# make # CROSS=x86_64 by default as shown in the first line.
# make CROSS=x86_64 # Make it explicit.
# make CROSS=i686 # Choose 32 bit.
What does it happen with dependencies like QtSql?
如您所见,您将依赖项视为其他普通库:使用 -l
选项指定它,但现在使用 Wl,-Bstatic
(说链接器链接必须是静态的),并指定使用 -L
选项交叉编译库的确切位置,如上面的代码所示。此外,在那个 makefile
中我添加了 -lwinmm
和 -loleut32
因为它们是下降的依赖项。
无论如何,由于链接器的原因,此 makefile 无法完全编译,但要正常工作,您只需添加其他间接需要的库和选项(参见 qmake
生成的 makefile
) .不管怎样,主要的configuration
问题都在上面的makefile
中显示了。
And with moc?
工具 moc
是一个预处理器,因此与机器无关 (AFAIK)。因此,您可以使用本地安装的 moc 将 moc
传递给您的文件。不管怎样,MXE 当然也安装了一个特定于平台的 moc
:
MXE_MOC=$(MXE_USR)/qt/bin/moc
mymoc1: header1.hpp
$(MXE_MOC) $< -o $@
但我不认为 MXE 的 moc
和你的有什么重要区别,除了 MXE 版本可能更现代(我不知道)。
Additionally, should I define LD, AR or PKG_CONFIG variables as the tutorial says?
没有必要。如果您不显式使用它们,则无需定义它们。
I've read that mingw has troubles working with templates, and I make a deep use of them in my project.
错误。当前的 MXE 版本安装了 gcc
5.1.0 的 mingw32
forge,效果很好。
.pro
文件呢?
MXE = /usr/local/mxe/usr/$$CROSS
MXE_INCL = $$MXE/include
MXE_LIB = $$MXE/lib
MXE_QT = $$MXE/qt
MXE_QTINCL = $$MXE_QT/include
MXE_QTLIB = $$MXE_QT/lib
TARGET = myapp # .exe no required.
OBJS = main.o
MOC_HEADERS = mymoc1.hpp mymoc2.hpp
HEADERS = $$MOC_HEADERS other-headers
SOURCES = main.cpp
QMAKE_CXX = $${CROSS}-g++
QMAKE_CXXFLAGS = -static -std=c++11 -pedantic -pedantinc-errors -Wall
QMAKE_LFLAGS += -Xlinker -Bstatic
INCLUDE_PATH += $$MXE_QTINCL $$MXE_QTINCL/QtGui $$MXE_QTINCL/QtSql
TEMPLATE = app
CONFIG += qt release
QT += core gui sql
LIBS += -L$$MXE_QTLIB -L$$MXE_LIB
# Call it (for x86_64):
# /usr/local/mxe/usr/x86_64-w64-mingw32.static/qt/bin/qmake\
# -makefile -o cross_makefile -nomoc CROSS=x86_64 myapp.pro
# make -f cross_makefile
如你所见,我说 qmake
不要生成 moc
文件(选项 -nomoc
),因为出于某些奇怪的原因,qmake
是无法在这么多模板中找到我的 Q_OBJECT
。所以,我之前必须手动生成它们。我真正做的是用生成 moc
文件然后自动调用 cross
的目标调用 cross
修改我的原始 makefile(我用来为 Linux 编译项目的那个) 14=] 具有适当的选项。
我有一个项目使用 Qt4,没有额外的库和 QtSql(用于使用 SQLLite 数据库),我想为 x86_64 Windows 7 机器交叉编译它。这是我总结的 makefile(除了 main.cpp,它只使用 .hpp 文件,因为我使用了很多模板):
CXX=g++-4.8
CXXFLAGS=-std=c++11 -pedantic -Wall -pedantic-errors -Wextra
IPATH=-I/usr/include/qt4/ -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtSql
LDFLAGS=-lQtGui -lQtSql -lQtCore
OBJS=main.o
HEADERS=mymoc1.hpp mymoc2.hpp other-headers
all: myexec
myexec: $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $@ $(LDFLAGS)
main.o: main.cpp $(HEADERS)
$(CXX) -c $(CXXFLAGS) $< -o $@ $(IPATH)
mymoc1.hpp: the-header-needing-moc.hpp
moc $< -o $@
mymoc2.hpp: other-header-needing-moc.hpp
moc $< -o $@
我要学习下一个教程:http://mxe.cc/#tutorial 假设我已经成功完成了前四个步骤,我的疑问来自于在 5c 和 5d 步骤之间进行选择。在我的情况下我应该使用什么以及如何使用?像 QtSql 这样的依赖会发生什么?还有 moc?
此外,我是否应该按照教程中的说明定义 LD、AR 或 PKG_CONFIG 变量?我没有在原始 makefile 中指定链接器或汇编器。如果我应该,为什么?
编辑 我读过 here mingw
在使用模板时遇到问题,我在我的项目中深入使用了它们。由于 MXE 在内部使用 mingw
,我是否应该考虑其他替代方案(例如直接在 Windows 中构建)而不是使用 MXE?
我将在这里 post 我自己的答案,但充满了细节,因为我很迷茫,也许其他用户也处于类似情况。
I am going to follow the next tutorial: http://mxe.cc/#tutorial Supposing I've complete successfully the first fourth steps, my doubt comes from choosing between 5c and 5d steps. What shall I use and how in my case?
是的,您(我确实是在回答我自己的问题)可以使用 Makefile 交叉编译静态链接的 Qt 项目。问题是,由于 Qt 是静态链接的,任何其他 Qt 依赖项也必须是静态链接的,这会创建一个潜在的长字符串库依赖项以添加到您的 Makefile 中(并且您还需要知道要传递的正确选项到链接器)。问题是这些选项或库中的一些在 windows-specific 旁边,因此,如果您以前从未为 Windows 编译过程序,那么您很难知道它们是什么以及它们的用途.
出于这个原因,您可以做的最好的事情就是编写自己的 .pro
文件来创建一个带有 qmake
的工作 Makefile。在这一点上,如果你仍然想制作你的自定义 Makefile,你可以执行 qmake
生成的 makefile
并查看执行的命令,复制回来并在你的自定义 Makefile 中进行试验。
无论如何,我会 post 我到达的最远的地方 makefile
(稍后在这个 post 我将展示我的工作 *.pro
文件的样子)。它编译成功,但是在链接时崩溃了,因为有很多未解决的依赖关系我无法按照上面的方法修复(我的 mxe 安装在 `/usr/local/mxe):
ifndef CROSS
CROSS=x86_64
endif
CROSS_ID=$(CROSS)-w64-mingw32.static
MXE_BASE=/usr/local/mxe/usr
MXE_USR=$(MXE_BASE)/$(CROSS_ID)
MXE_INCL=$(MXE_USR)/include
MXE_QTINCL=$(MXE_USR)/qt/include
MXE_LIB=$(MXE_USR)/lib
MXE_QTLIB=$(MXE_USR)/qt/lib
LDIFLAGS=-I$(MXE_INCL) -I$(MXE_QTINCL)/QtCore -I$(MXE_QTINCL)/QtGui -I$(MXE_QTINCL)/QtSql
LDLFLAGS=-L$(MXE_LIB) -L$(MXE_QTLIB)
LDLIBS=-Wl,-Bstatic -lwinmm -loleut32 -lQtGui -lQtSql -lQtCore
CXX=$(MXE_PATH)/bin/$(CROSS_ID)-g++
CXXFLAGS=-std=c++11 -pedantic -pedantic-errors -Wall
OBJS=main.o
MOC_HEADERS=mymoc1.hpp mymoc2.hpp
HEADERS=$(MOC_HEADERS) myheaders
APP=myapp.exe
all: $(APP)
$(APP): $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $@ $(LDLFLAGS) $(LDLIBS)
main.o: main.cpp $(HEADERS)
$(CXX) $(CXXFLAGS) $< -o $@ $(LDIFLAGS)
mymoc1: header1.hpp
moc $< -o $@
mymoc2: header2.hpp
moc $< -o $@
# Thee ways of call it:
# make # CROSS=x86_64 by default as shown in the first line.
# make CROSS=x86_64 # Make it explicit.
# make CROSS=i686 # Choose 32 bit.
What does it happen with dependencies like QtSql?
如您所见,您将依赖项视为其他普通库:使用 -l
选项指定它,但现在使用 Wl,-Bstatic
(说链接器链接必须是静态的),并指定使用 -L
选项交叉编译库的确切位置,如上面的代码所示。此外,在那个 makefile
中我添加了 -lwinmm
和 -loleut32
因为它们是下降的依赖项。
无论如何,由于链接器的原因,此 makefile 无法完全编译,但要正常工作,您只需添加其他间接需要的库和选项(参见 qmake
生成的 makefile
) .不管怎样,主要的configuration
问题都在上面的makefile
中显示了。
And with moc?
工具 moc
是一个预处理器,因此与机器无关 (AFAIK)。因此,您可以使用本地安装的 moc 将 moc
传递给您的文件。不管怎样,MXE 当然也安装了一个特定于平台的 moc
:
MXE_MOC=$(MXE_USR)/qt/bin/moc
mymoc1: header1.hpp
$(MXE_MOC) $< -o $@
但我不认为 MXE 的 moc
和你的有什么重要区别,除了 MXE 版本可能更现代(我不知道)。
Additionally, should I define LD, AR or PKG_CONFIG variables as the tutorial says?
没有必要。如果您不显式使用它们,则无需定义它们。
I've read that mingw has troubles working with templates, and I make a deep use of them in my project.
错误。当前的 MXE 版本安装了 gcc
5.1.0 的 mingw32
forge,效果很好。
.pro
文件呢?
MXE = /usr/local/mxe/usr/$$CROSS
MXE_INCL = $$MXE/include
MXE_LIB = $$MXE/lib
MXE_QT = $$MXE/qt
MXE_QTINCL = $$MXE_QT/include
MXE_QTLIB = $$MXE_QT/lib
TARGET = myapp # .exe no required.
OBJS = main.o
MOC_HEADERS = mymoc1.hpp mymoc2.hpp
HEADERS = $$MOC_HEADERS other-headers
SOURCES = main.cpp
QMAKE_CXX = $${CROSS}-g++
QMAKE_CXXFLAGS = -static -std=c++11 -pedantic -pedantinc-errors -Wall
QMAKE_LFLAGS += -Xlinker -Bstatic
INCLUDE_PATH += $$MXE_QTINCL $$MXE_QTINCL/QtGui $$MXE_QTINCL/QtSql
TEMPLATE = app
CONFIG += qt release
QT += core gui sql
LIBS += -L$$MXE_QTLIB -L$$MXE_LIB
# Call it (for x86_64):
# /usr/local/mxe/usr/x86_64-w64-mingw32.static/qt/bin/qmake\
# -makefile -o cross_makefile -nomoc CROSS=x86_64 myapp.pro
# make -f cross_makefile
如你所见,我说 qmake
不要生成 moc
文件(选项 -nomoc
),因为出于某些奇怪的原因,qmake
是无法在这么多模板中找到我的 Q_OBJECT
。所以,我之前必须手动生成它们。我真正做的是用生成 moc
文件然后自动调用 cross
的目标调用 cross
修改我的原始 makefile(我用来为 Linux 编译项目的那个) 14=] 具有适当的选项。