How to compile simple Qt 5.2 project in C4Droid

10,804

This answer can be seen as a

mini-tutorial to compile and export Qt projects in C4droid.

how to build and compile a simple Qt project in C4Droid, an C++ compiler for Android?

I've created a simple project in Qt Creator for Qt 4.8, compiled the .ui form, and adapted the code from Qt 4.8 to Qt 5.2. The project itself is very simple: A form with a QButton and a QLineEdit. When QButton is pressed, "Hello world" appears in QLineEdit.

These are the files I've posted in my C4droid test folder:

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();
}

mainwindow.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

mainwindow.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"));
}

mainwindow.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>

Now, open ButtonHelloWorld.pro or main.cpp from C4Droid. Long-tap Compile, selected "Makefile" compilation mode and "Qt application" run mode, and "libButtonHelloWorld.so" as executable file.

This is important: In Android Qt executables are always named libXXX.so. The executable name must be lib[NameOf.proFileWithoutExtension].so, and it's folder-name independant.

Once compiled and tested it runs OK, to export it to an .APK is so easy as Menu->Export.

I've tried it and... it's amazing!!

PS: If you wonder where are the moc, qmake, rcc and uic executables, they are in /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/ folder (at least, in my android).

Share:
10,804
Bull
Author by

Bull

Worked recently with C++, Qt, OpenCV, PointCloud and several Time of Flight cameras under Linux (Ubuntu). Currently involved in C++ and Wt (Web Toolkit, AKA "Witty") developing, under Linux and Windows. Active developer in Microsoft Dynamics Ax and related technologies. Very interested in cross-developing between platforms and operative systems.

Updated on June 09, 2022

Comments

  • Bull
    Bull almost 2 years

    I'm trying to figure how to build and compile a simple Qt project in C4Droid, an C++ compiler for Android.

    The program comes with 2 simple examples: An "Hello world" Label (one file), and a example Notepad. The second one, seems interesting, but it deals with forms creating them entirely from code.

    I'm investigating if doing this with forms generated from .ui files is possible. I've created a simple project in Qt Creator for Qt 4.8, compiled the .ui form, and adapted the code from Qt 4.8 to Qt 5.2. The project itself is very simple: A form with a QButton and a QLineEdit. When QButton is pressed, "Hello world" appears in QLineEdit.

    AS far as I've seen, C4Droid doesn't parse .pro files. To compile project, I must open main.cpp and long-tap "compile", select "Compile multiple source code files (simple)", and then run. C4droid uses it's own "makefile" file, in a .c4droid text file.

    These are the files I've posted in my C4droid test folder:

    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();
    }
    

    mainwindow.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
    

    mainwindow.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
    

    I put here the original mainwindow.ui for reference (c4droid does not use it):

    <?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>
    

    When I try to compile this project from main.cpp in C4droid, the output is:

    /storage/emulated/0/Bull/C4Droid/ButtonHelloWorld/main.cpp:0: Note: No relevant classes found. No output generated. /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o: In function MainWindow::MainWindow(QWidget*)': mainwindow.cpp:(.text+0xc4): undefined reference tovtable for MainWindow' /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o: In function MainWindow::~MainWindow()': mainwindow.cpp:(.text+0x14c): undefined reference tovtable for MainWindow' /data/data/com.n0n3m4.droidc/files/gcc/tmpdir/ccyCC2RV.o: In function MainWindow::tr(char const*, char const*, int)': mainwindow.cpp:(.text._ZN10MainWindow2trEPKcS1_i[_ZN10MainWindow2trEPKcS1_i]+0x5c): undefined reference toMainWindow::staticMetaObject' collect2: error: ld returned 1 exit status

    What can I do to compile successfully this project?

    Of course, I've googled a lot, and tried to include .moc files everywere with no luck.

    (By the way, I just tried now to create the tag "C4Droid", but I haven't enough reputation to do that :-/)

    Update 1 --- Looking carefully the multiple files Qt example shipped with C4droid, I've noticed that it uses Makefile. Reading Makefile, I've noticed that this file was generated using the command:

    /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/qmake -spec android-g++ -o Makefile application.pro

    (This also made me to know that moc, qmake, rcc and uic executables are in /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/ folder in my android)

    This should create a Makefile according to file .pro, that automatically tells the system to use uic, moc, etc before compiling, and doing the proper linkings after that. So I entered in Terminal in my android and typed:

    /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/qmake -spec android-g++ -o Makefile ButtonHelloWorld.pro

    All I get is:

    sh: arm-linux-androideabi-gcc: not found

    Update 2

    The C4droid developer responsed me:

    "C4droid can parse .pro files, look at the examples carefully. The description on Google Play is the only tutorial available, but it is enough."

    So I decided to go to my .pro file in C4droid. After looking the example compile options, I decided to long-press compile, selected "Makefile" compilation mode and "Qt application" run mode, and "ButtonHelloWorld.qexe" as executable file.

    I now compiles and all appears to go much better, but at end this message pops:

    Failed to copy file

    Any hints?

    Update 3

    OK, I tested and played (a lot) with the example Qt appl bundled I emailed again the developer, and it now has been absolutly handy.

    Me:

    I've decided to do a test with your example. I've copied to a new folder (/storage/emulated/0/Bull/C4Droid/application)

    images folder
    application.pro
    application.qrc
    main.cpp
    mainwindow.cpp
    mainwindow.h
    

    Then, in C4droid, I open application.pro, long-tap "Compile". Select "Makefile" compilation mode and "Qt application" run mode, and put an executable file "pplication.so". It compiles OK, but fails with "Failed to copy file".

    But if I put "libapplication.so" as executable file, it compiles and finishes OK.

    ¿Why?

    He:

    Because on Android Qt executables are always named libXXX.so

    Me:

    Well, I tried "libappli.so" and got same error.

    But, Investigating this, I've seen that executable name must be lib[NameOf.proFileWithoutExtension].so, and it's folder-name independant. Now your copied example and mine work!!

    And also, he told me that once compiled, export it to an .APK is so easy as Menu->Export. I've tried it and... it's amazing!!

    Conclusion

    Solved. Answering my own Question in order to help others in my same situation.

  • László Papp
    László Papp almost 10 years
    So, you have to create the moc file by running 'moc -o mainwindow.moc inputfile` and then compile the generated moc file as usual, e.g. g++ ... mainwindow.moc.
  • Bull
    Bull almost 10 years
    According to your suggestion, I entered in Terminal, went to my project folder, and typed: /data/data/com.n0n3m4.droidc/files/gcc/qt/bin/moc mainwindow.h -o mainwindow.h.moc After that, no luck in compiling. What more should I do?
  • László Papp
    László Papp almost 10 years
    I do not know what no luck means, but like I said before you have to do two steps, where you only did one.
  • László Papp
    László Papp almost 10 years
    Have you read this part of my comment? and then compile the generated moc file as usual, e.g. g++ ... mainwindow.moc.
  • Bull
    Bull almost 10 years
    I've ask the C4droid developer about this, and his answer was (just now): "C4droid can parse .pro files, look at the examples carefully. The description on Google Play is the only tutorial available, but it is enough." Will review both again (one more time)
  • Bull
    Bull almost 10 years
    Laszlo, you're right, compiling the moc just generates a normal cpp file that can be compiled and linked as usual. Thanks for your suggestions.
  • Bull
    Bull almost 10 years
    Well, your suggestion was a good point, but wasn't the solution at all
  • László Papp
    László Papp almost 10 years
    There is an official tutorial already, basically... It is amazing you have not linked that. ;)
  • Bull
    Bull almost 10 years
    I googled a lot but found anything. Only app description in Google Play was available, ant it was too concise and unclear for me. Tell me the link you're referring, and I will gladly include it in my post.