如何在 C4Droid 中编译简单的 Qt 5.2 项目
Posted
技术标签:
【中文标题】如何在 C4Droid 中编译简单的 Qt 5.2 项目【英文标题】:How to compile simple Qt 5.2 project in C4Droid 【发布时间】:2014-05-04 23:25:23 【问题描述】:我试图弄清楚如何在 C4Droid 中构建和编译一个简单的 Qt 项目,这是一个适用于 android 的 C++ 编译器。
该程序带有 2 个简单的示例:一个“Hello world”标签(一个文件)和一个示例记事本。第二个似乎很有趣,但它处理的表单完全由代码创建。
我正在调查是否可以使用从 .ui 文件生成的表单来执行此操作。我在 Qt Creator 中为 Qt 4.8 创建了一个简单的项目,编译了 .ui 表单,并将代码从 Qt 4.8 改编为 Qt 5.2。项目本身非常简单:一个带有 QButton 和 QLineEdit 的表单。当按下 QButton 时,QLineEdit 中会出现“Hello world”。
据我所知,C4Droid 不解析 .pro 文件。要编译项目,我必须打开 main.cpp 并长按“编译”,选择“编译多个源代码文件(简单)”,然后运行。 C4droid 在 .c4droid 文本文件中使用它自己的“makefile”文件。
这些是我在 C4droid 测试文件夹中发布的文件:
ButtonHelloWorld.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ButtonHelloWorld
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
main.cpp:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
主窗口.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui
class MainWindow;
class MainWindow : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_ButtonSayHello_clicked();
private:
Ui::MainWindow *ui;
;
#endif // MAINWINDOW_H
主窗口.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
ui->setupUi(this);
MainWindow::~MainWindow()
delete ui;
void MainWindow::on_ButtonSayHello_clicked()
ui->LeditSayHello->setText(tr("Hello world"));
ui_mainwindow.h:
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QAction>
#include <QApplication>
#include <QButtonGroup>
#include <QHeaderView>
#include <QLineEdit>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout;
QPushButton *ButtonSayHello;
QLineEdit *LeditSayHello;
void setupUi(QMainWindow *MainWindow)
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(198, 103);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
verticalLayout = new QVBoxLayout(centralWidget);
verticalLayout->setSpacing(6);
verticalLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
ButtonSayHello = new QPushButton(centralWidget);
ButtonSayHello->setObjectName(QString::fromUtf8("ButtonSayHello"));
verticalLayout->addWidget(ButtonSayHello);
LeditSayHello = new QLineEdit(centralWidget);
LeditSayHello->setObjectName(QString::fromUtf8("LeditSayHello"));
LeditSayHello->setAlignment(Qt::AlignCenter);
verticalLayout->addWidget(LeditSayHello);
MainWindow->setCentralWidget(centralWidget);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
// setupUi
void retranslateUi(QMainWindow *MainWindow)
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
ButtonSayHello->setText(QApplication::translate("MainWindow", "Say Hello", 0));
// retranslateUi
;
namespace Ui
class MainWindow: public Ui_MainWindow ;
// namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
我把原来的mainwindow.ui放在这里供参考(c4droid不用):
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>198</width>
<height>103</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="ButtonSayHello">
<property name="text">
<string>Say Hello</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="LeditSayHello">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
当我尝试在 C4droid 中从 main.cpp 编译这个项目时,输出是:
/storage/emulated/0/Bull/C4Droid/ButtonHelloWorld/main.cpp:0:注意:否 找到相关的类。没有产生输出。 /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o:在函数中
MainWindow::MainWindow(QWidget*)': mainwindow.cpp:(.text+0xc4): undefined reference to
vtable for MainWindow' /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o:在函数中MainWindow::~MainWindow()': mainwindow.cpp:(.text+0x14c): undefined reference to
vtable for MainWindow' /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o:在函数中MainWindow::tr(char const*, char const*, int)': mainwindow.cpp:(.text._ZN10MainWindow2trEPKcS1_i[_ZN10MainWindow2trEPKcS1_i]+0x5c): undefined reference to
MainWindow::staticMetaObject' collect2: 错误: ld 返回 1 个退出状态
如何才能成功编译这个项目?
当然,我在 Google 上搜索了很多,并尝试包含 .moc 文件,但都没有成功。
(顺便说一句,我现在刚刚尝试创建标签“C4Droid”,但我没有足够的声誉来做到这一点:-/)
更新 1 --- 仔细查看 C4droid 附带的多个文件 Qt 示例,我注意到它使用 Makefile。阅读 Makefile,我注意到这个文件是使用命令生成的:
/data/data/com.n0n3m4.droidc/files/gcc/qt/bin/qmake -spec android-g++ -o Makefile application.pro
(这也让我知道 moc、qmake、rcc 和 uic 可执行文件位于我的 android 的 /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/ 文件夹中)
这应该根据文件 .pro 创建一个 Makefile,它会在编译之前自动告诉系统使用 uic、moc 等,然后进行正确的链接。所以我在我的android中输入了终端并输入:
/data/data/com.n0n3m4.droidc/files/gcc/qt/bin/qmake -spec android-g++ -o Makefile ButtonHelloWorld.pro
我得到的是:
sh: arm-linux-androideabi-gcc: 未找到
更新 2
C4droid 开发者回复我:
“C4droid可以解析.pro文件,仔细看例子。Google Play上的描述是唯一可用的教程,但已经足够了。”
所以我决定在 C4droid 中访问我的 .pro 文件。看了示例编译选项后,决定长按编译,选择“Makefile”编译模式和“Qt应用”运行模式,选择“ButtonHelloWorld.qexe”作为可执行文件。
我现在编译,一切似乎都好得多,但最后会弹出这条消息:
复制文件失败
有什么提示吗?
更新 3
好的,我用捆绑的示例 Qt appl 测试和玩了(很多)我再次通过电子邮件发送给开发人员,现在它已经非常方便了。
我:
我决定用你的例子做一个测试。我已复制到一个新文件夹(/storage/emulated/0/Bull/C4Droid/application)
images folder application.pro application.qrc main.cpp mainwindow.cpp mainwindow.h
然后,在 C4droid 中,我打开 application.pro,长按“编译”。选择 “Makefile”编译模式和“Qt应用”运行模式,并放一个 可执行文件“application.so”。它编译正常,但失败 “复制文件失败”。
但如果我将“libapplication.so”作为可执行文件,它会编译并 完成OK。
¿为什么?
他:
因为在 Android Qt 上,可执行文件总是被命名为 libXXX.so
我:
好吧,我尝试了“libappli.so”并得到了同样的错误。
但是,对此进行调查,我发现可执行文件名称必须是 lib[NameOf.proFileWithoutExtension].so,它是文件夹名称 独立的。现在你复制的例子和我的工作!!
而且,他告诉我,一旦编译,将其导出为 .APK 就像 Menu->Export 一样简单。我试过了……太棒了!!
结论
解决了。回答我自己的问题,以帮助遇到同样情况的其他人。
【问题讨论】:
【参考方案1】:这个答案可以看成是一个
在 C4droid 中编译和导出 Qt 项目的迷你教程。
如何在 Android 的 C++ 编译器 C4Droid 中构建和编译一个简单的 Qt 项目?
我在 Qt Creator 中为 Qt 4.8 创建了一个简单的项目,编译了 .ui 格式,并将代码从 Qt 4.8 改编为 Qt 5.2。项目本身非常简单:一个带有 QButton 和 QLineEdit 的表单。当按下 QButton 时,QLineEdit 中会出现“Hello world”。
这些是我在 C4droid 测试文件夹中发布的文件:
ButtonHelloWorld.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ButtonHelloWorld
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
main.cpp:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
主窗口.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui
class MainWindow;
class MainWindow : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_ButtonSayHello_clicked();
private:
Ui::MainWindow *ui;
;
#endif // MAINWINDOW_H
主窗口.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
ui->setupUi(this);
MainWindow::~MainWindow()
delete ui;
void MainWindow::on_ButtonSayHello_clicked()
ui->LeditSayHello->setText(tr("Hello world"));
主窗口.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>198</width>
<height>103</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="ButtonSayHello">
<property name="text">
<string>Say Hello</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="LeditSayHello">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
现在,从 C4Droid 打开 ButtonHelloWorld.pro 或 main.cpp。长按编译,选择“Makefile”编译模式和“Qt应用”运行模式,将“libButtonHelloWorld.so”作为可执行文件。
这很重要:在 Android Qt 中,可执行文件始终命名为 libXXX.so。 可执行文件名必须是 lib[NameOf.proFileWithoutExtension].so,且与文件夹名无关。
编译和测试后运行正常,将其导出为 .APK 就像 Menu->Export 一样简单。
我试过了……太棒了!!
PS:如果你想知道 moc、qmake、rcc 和 uic 可执行文件在哪里,它们在 /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/ 文件夹中(至少在我的 android )。
【讨论】:
已经有一个官方教程了,基本上......你没有链接它真是太棒了。 ;) 我用谷歌搜索了很多,但什么都没找到。只有 Google Play 中的应用程序描述可用,对我来说太简洁和不清楚。告诉我您所指的链接,我很乐意将其包含在我的帖子中。【参考方案2】:您忘记为您的主窗口处理元对象编译器,简称“moc”文件。没有它,你将无法让 QObject 机制正常工作。
您需要执行以下任一操作:
moc -o mainwindow.moc mainwindow.h
g++ ... mainwindow.moc
作为构建过程的一部分,即通过显式运行 moc 扩展 Makefile 并将 *.moc 模式添加到要编译的文件列表中,或者通过它单独运行编译器命令。
另外,C4Droid 似乎从 3.49 版开始支持 qmake 项目文件。
【讨论】:
所以,你必须通过运行'moc -o mainwindow.moc inputfile`来创建moc文件,然后像往常一样编译生成的moc文件,例如g++ ... mainwindow.moc
.
根据你的建议,我进入终端,进入我的项目文件夹,输入:/data/data/com.n0n3m4.droidc/files/gcc/qt/bin/moc mainwindow.h -o mainwindow.h.moc 之后,编译就没有运气了。我还应该做什么?
我不知道没有运气是什么意思,但就像我之前说的你必须做两步,而你只做了一个。
你读过我的这部分评论吗? and then compile the generated moc file as usual, e.g. g++ ... mainwindow.moc.
我问过 C4droid 开发者,他的回答是(刚刚):“C4droid 可以解析 .pro 文件,仔细看例子。Google Play 上的描述是唯一的教程可用,但已经足够了。”将再次审查(再一次)以上是关于如何在 C4Droid 中编译简单的 Qt 5.2 项目的主要内容,如果未能解决你的问题,请参考以下文章
使用 Qt 5.3 或 Qt 5.4(但不是 Qt 5.2)编译时,QGuiApplication 在手机锁定时停止事件循环
如何使用 QT 5.2 在 android 上删除发布输出中的调试模式