如何在 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 tovtable for MainWindow' /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o:在函数中 MainWindow::~MainWindow()': mainwindow.cpp:(.text+0x14c): undefined reference tovtable 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 toMainWindow::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 上删除发布输出中的调试模式

C4droid:安卓手机最强C/C++编译器

C4droid:安卓手机最强C/C++编译器

编译Qt5.0连接MySql5.5数据库的驱动(5.0版本的编译,我记得5.2开始自带了)

Android Hello World Qt 5.2