arm Mac で C/C++ ライブラリを x86_64 向けにビルドする

すっかり arm 環境に移行した感のある Mac 界隈だが、なんらかの事情で Intel Mac 向けにアプリなどをビルドしたいという場合がある(案件だとね)。

アプリ自体は Xcode 上での操作でなんとかなると思うのだが、厄介なのはライブラリの類。

使いたい C/C++ のライブラリを M1/M2 Mac 上で x86_64 向けにビルドする必要が出てくる。
いわゆるクロスコンパイルというやつだ。

iOS の場合、simulator が x86_64 でしか動かないので、この手の情報はけっこうあったのだが、 MacOS 向けの情報は皆無だった。

試行錯誤したところ configure 時に以下のようなにコンパイルオプションを与えると、クロスコンパイルできるようだ。

./configure --prefix=/dir/hoge x86_64-apple-darwin64 CFLAGS='-arch x86_64 -O2 -g'

あとは make, make install でいけるっぽい。

–build オプションを使えとか、それっぽい情報はあるにはあった。
が、実行しても惜しいところまではいくんだが、なぜか最終的にはうまくいかなかった。

 

Xcode -aggeragate target-

ところで、であるが、アイキャッチの赤い三重丸のようなやつの正式名称を知っているだろうか?

aggeregate target

どことなく射的の的を連想させるアイコン(ターゲット)は aggeregate というらしい。

英単語としての発音は「アーグリゲイト」、一般的な意味は「集約する、合計する」だ。

日本語の情報はほとんどなく

ライブラリ・SDKにSwiftLintを導入するベストプラクティス

でかろうじて触れられているのみ。

aggregate target を生成するのもややクセがあって、

File -> New -> Target…

として(↓)、

ダイアログを表示させ iOS や macOS ではなく other の方を選ぶ。

これは調べないと分かりませんね。

参考

その他、Xcode やビルドシステムについて。

・cmake 単体で iOS のプロジェクトを取り扱う。

cmakeを使ってxcodeを使わずにiosアプリを作成する

・cmake で Xcode のプロジェクトファイルを生成する。

CMakeとIDEを連携させる

help によれば cmake で framework を直接生成できるらしいのだが、試したことはない。
(→結局、試しました

余談 -External Build System-

ところで、アーグリゲイトなターゲットを作成する際、こういう画面が出てくる。

気になるのは External Build Sysytem だと思うが、イマイチ使い方がわからない。

デフォルトだと make を使うように設定されているのだが、aggregate ターゲットでもいけるはずだが???

余裕があったら、調べます。

余談 Xcode での C++ 標準ライブラリのヘッダーファイルの置き場所

Xcode14 では

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1

です。

よく移動になるみたいですね。

標準ライブラリのヘッダーファイルが見つからない場合は、上のフォルダを header search paths に設定する。

 

C++ 感覚を取り戻す

IT 業界でフリーでやっている若い世代は、仕事を選べる立場にある人はそんなに多くはないと思う。

そんな時に C++ 案件が舞い込んでくると、意外に基礎がすっぽりと抜けてたりする。

そういうわけで急いで C++ 感覚を取り戻すためのメモ。

ワイの場合、Objective-C や Qt も扱っているので、この変更が意外に手間かかったりする。
「似ているようで違う」というのは、思っている以上にタチ悪いかも(笑)。

ハロワ

あまり C++ っぽくはないが、まあ基礎。

//hello.cpp
#include <iostream>

int main(){
    std::cout << "hello world";
}

ソース自体は C とあまり変わらない。

が、コンパイルは

g++ -o hello hello.cpp

または

clang++ -o hello hello.cpp

とする。
gcc や clang では、c と解釈するのかエラーになる。

 

(続く。『江添 C++ 本と本家ストラウストラップ本』あたりもご参考に)

QxOrm で簡単なサンプルを書いてみる

以前に書いた QxOrm の記事が(日本においてはおそらく)最初の解説記事だったらしく、ちょいちょい反応があった。

ネット上でも gitlove さんという方が、簡単なサンプルを書いてくれた。

クラスの定義や main 関数での QxOrm の操作はそこに書かれているコードほぼそのままでいいと思います。

ただ、(チュートリアルでもあまり強調されていないが)QxOrm を使う際のオマジナイみたいなもので、export.h というファイルが必要なようです。

target = test としたとき、まず .pro ファイルで _BUILDING_TEST を定義しておき、export.h で各種マクロを定義します。

具体的には以下の通り。

//export.h
#ifndef _QX_TEST_EXPORT_H_
#define _QX_TEST_EXPORT_H_

#ifdef _BUILDING_QX_TEST
#define QX_TEST_DLL_EXPORT QX_DLL_EXPORT_HELPER
#else
#define QX_TEST_DLL_EXPORT QX_DLL_IMPORT_HELPER
#endif

#ifdef _BUILDING_QX_TEST
#define QX_REGISTER_HPP_QX_TEST     QX_REGISTER_HPP_EXPORT_DLL
#define QX_REGISTER_CPP_QX_TEST     QX_REGISTER_CPP_EXPORT_DLL
#else
#define QX_REGISTER_HPP_QX_TEST     QX_REGISTER_HPP_IMPORT_DLL
#define QX_REGISTER_CPP_QX_TEST     QX_REGISTER_CPP_IMPORT_DLL
#endif

#endif

このファイルを precompiled.h に include しておき、main から使えるようにしておく、という構成です。

マクロを定義したので、ソースも適宜変更。

//person.h
#ifndef _CLASS_PERSON_H_
#define _CLASS_PERSON_H_

class person
{
public:

   long id;
   QString name;

   person() :id(0) { ; }
   virtual ~person() { ; }

};

QX_REGISTER_HPP_QX_TEST(person, qx::trait::no_base_class_defined,1)//←これを追加

#endif // _CLASS_PERSON_H

person.cpp も以下のように変更。


#include "../include/precompiled.h"

#include "../include/person.h"

#include <QxOrm_Impl.h>

QX_REGISTER_CPP_QX_TEST(person)//←追加

namespace qx {
template &lt;> void register_class(QxClass<person> & t)
{
   t.id(& person::id, "id");

   t.data(& person::name, "name");
}}

main.cpp


#include "../include/precompiled.h"

#include <QtCore/qcoreapplication.h>
#include "../include/person.h"

#include <QxOrm_Impl.h>

int main(int argc, char * argv[])
{
   // Qt application
   QCoreApplication app(argc, argv);
   QFile::remove("./person.db");

   typedef std::shared_ptr<person> person_ptr;
   person_ptr d1; d1.reset(new person()); d1->name = "name1";

   typedef std::vector<person_ptr> type_lst_person;
   type_lst_person lst_person;
   lst_person.push_back(d1);

   // Parameters to connect to database
   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./person.db");
   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
   qx::QxSqlDatabase::getSingleton()->setUserName("root");
   qx::QxSqlDatabase::getSingleton()->setPassword("");
   qx::QxSqlDatabase::getSingleton()->setFormatSqlQueryBeforeLogging(true);
   qx::QxSqlDatabase::getSingleton()->setDisplayTimerDetails(true);

   // Only for debug purpose : assert if invalid offset detected fetching a relation
   qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true);

   // Create all tables in database
   QSqlError daoError = qx::dao::create_table<person>();

   person_ptr person_1; person_1.reset(new person());
   person_1->id = 1; person_1->name = "秋葉 太郎";

   daoError = qx::dao::insert(person_1);

   return 0;
}

これで、ビルドして、実行すると出力先に test(d) という実行ファイルと person.db という sqlite のデータベースができているはずです。

DB Browser for SQLite などで覗いてみると…

できてますね!

注意点

①上では、従来の .pro ファイルを使う qmake でビルドしています。

なのですが、cmake でビルドしようとすると QxOrm のライブラリが見つからない場合があるようです。

これは QxOrm の cmake ビルドシステム自体が未整備のためのようです。関連の PR がありました。

開発者さん自身は、しばらくは qmake メインでいきたいようです。

ワイは、こんなことを提案してきました。

cmake が他のパッケージをどうやって探しているかまっっったく理解してませんが。

参考:

https://qiita.com/shohirose/items/d9bda00a39a113965c5c

②他には postgreSQL が繋がらないかな。

qx::QxSqlDatabase::getSingleton()->setDriverName("QPSQL");

としたでのは、ドライバーがロードできない云々というエラーが出る。

Qt あれこれ

久方ぶりに Qt を触っているんだが、Qt 自体は進化している。

日本の Qt 事情

なのだが、日本の Qt 事情はお寒い。

まず、日本語で書かれたオリジナルの Qt 関係の本はほぼない。

唯一あるとすれば、これ↓。

まあ入門書でしょう。→ 括りとしては入門書なのでしょうが、細部に著者の Qt に対する洞察が散りばめられており、ここら辺は入門書の範疇を超えています。

レビューにもあるように

なお、表紙、裏表紙、背表紙すべてにあるロリ絵はやめて欲しいです。 恥ずかしい事この上ありません。 なぜ技術本にロリ絵を付けないといけないのかさっぱりわかりません。

ロリ絵というかアニメ絵というか。

頭のあたりに注目するとウマ娘意識してんのかな?と思わないでもない。

装丁は、まあ、賛否分かれるでしょう。

確かに Qt6 になって、Qt Creator の操作性はけっこう変わっている。

QML

一昔前の Qt GUI というと Qt Widget だったが、QML もかなり成長しているようだ。

この記事でも、将来は QML だろう、みたいなことが書かれている。

確かに、これはそうだよなあ。

Web アプリの作り方は、ほぼ大筋が固まっている。バックエンドとフロントエンド、UI とロジックの分離などなど。

このおかげで何をどうやって作成するのかという目標が持ちやすい。

おまけにブラウザの表現力は年々上がってきているし。

比較するのもアレだが Java の GUI 環境なんて今では陳腐に見える。

デスクトップもこの感覚で作りたい、というのは、当然の流れのように思える。

Qt5 → Qt6 何が変わったか?

vector の(内部的な)取り扱いが変わった。

上の本でも触れられているが、

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector vector;
    vector << 1 << 2;
    qDebug() << vector;


    return a.exec();
}

を走らせると QVector(1, 2) ではなくて

QList(1, 2)

と表示される。
要するに Qt5 時代の List を Vector にした模様。