[C++] 359 Makefileでワイルドカード使用 FLTKアプリ

[Mac M2 Pro 12CPU, Sonoma 14.3.1, clang++ 15.0.0, FLTK 1.3.9]

Homebrewのライブラリをアップデートする度にMakefileにあるバージョン番号を更新しなくて済むようワイルドカードに置き換えました。

さらにライブラリへのリンクを意味する-lを正常に動作させるため、-Lオプションに/opt/homebrew/libを追加しました。

これまでは/opt/homebrew/Cellarにある各ライブラリのlibパスをわざわざ記入していました。/opt/homebrew/libにライブラリファイルがまとめられているとは知らなかったです。

今回の修正で大分洗練されたMakefileになったように思います。

# コンパイラ
COMPILER = clang++
DEBUG = -g

# ビルドオプション
CPPFLAGS = $(shell fltk-config --use-gl --use-images --cxxflags ) -std=c++11
CPPFLAGS2 = $(shell pkg-config --cflags --libs opencv4 )
LDFLAGS = $(shell fltk-config --use-gl --use-images --ldflags ) -lc++

# includeパス(-I)
INCLUDE = -I./include -I/opt/homebrew/Cellar/libpng/*/include -I/opt/homebrew/Cellar/fltk/*/include \
-I/opt/homebrew/Cellar/opencv/*/include -I/opt/homebrew/Cellar/opencv/*/include/opencv4 \
-I/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10 \
-I/Volumes/DATA_m1/code/cpp/mylib/include

# リンク(-l)
LINK = -lz -lpng -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc -lpython3.10

# ライブラリパス(-L)
LIBRARY = -L/usr/local/lib -L/opt/homebrew/lib \
-L/Library/Frameworks/Python.framework/Versions/3.10/lib \
/Volumes/DATA_m1/code/cpp/mylib/lib/Split.a

# ソースファイル
SRCDIR = ./src
SRCS = $(shell find $(SRCDIR) -type f)

# オブジェクトファイル
OBJDIR = ./obj
OBJS = $(addprefix $(OBJDIR), $(patsubst ./src/%.cpp,/%.o,$(SRCS)))

# 実行ファイル
TARGETDIR = ./bin
TARGET = ImageInspector
	
# cppファイルからoファイル作成 $<:依存ファイル
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
	$(COMPILER) $(CPPFLAGS) $(CPPFLAGS2) $(INCLUDE) $(DEBUG) -o $@ -c $<

# アプリファイル作成関連
POSTBUILD  = fltk-config --post

# oファイルから実行ファイルとappファイル作成
$(TARGET):$(OBJS)
	$(COMPILER) -o $(TARGETDIR)/$@ $(OBJS) $(LINK) $(LIBRARY) $(LDFLAGS)
	cp $(TARGETDIR)/$(TARGET) $(TARGET)
	$(POSTBUILD) $(TARGET)
	mkdir $(TARGET).app/Contents/Resources
	cp ./images/$(TARGET).icns $(TARGET).app/Contents/Resources
	plutil -insert 'CFBundleIconFile' -string $(TARGET).icns $(TARGET).app/Contents/Info.plist
	rm -f $(TARGET)

# 全ソース強制コンパイル
.PHONY:all
all: clean $(TARGET)

# 全ファイル削除
.PHONY:clean
clean:
	rm -rf $(OBJS) $(TARGETDIR)/$(TARGET) $(TARGET).app

[C++] 358 FLTKアプリ ビルド時のトラブル png.h

[Mac M2 Pro 12CPU, Sonoma 14.3.1, clang++ 15.0.0, FLTK 1.3.9]

アイコン画像作成アプリを久しぶりにビルドすると、png関連のシンボルが見つからずエラーを吐くようになりました。

これまでlibpngのpng.hへアクセスしていたのが、FL/images/png.hを読み込むようになってしまったために起こったトラブルでした。

ヘッダファイルのincludeを絶対パスにすると直りました。

Homebrewのライブラリをアップデートするとバージョン番号が変わるのでMakefileを更新する必要がありますが、それとは関係なく起こったレアなトラブルだったため原因究明に時間が掛かりました。

ld: Undefined symbols:
  _fltk_png_create_info_struct, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_create_read_struct, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_destroy_read_struct, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_get_channels, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_get_image_height, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_get_image_width, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_get_x_pixels_per_inch, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_get_y_pixels_per_inch, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_init_io, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_read_png, referenced from:
      getInfoPNG(char const*) in processImage.o
  _fltk_png_set_sig_bytes, referenced from:
      getInfoPNG(char const*) in processImage.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:53: ImageInspector] Error 1
#ifndef PROCESSIMAGE_H
#define PROCESSIMAGE_H

#include <array>
// FL/imagesのpng.hを避けるため絶対パスに変更
#include "/opt/homebrew/Cellar/libpng/1.6.42/include/libpng16/png.h"

std::vector<std::string> split(std::string, char);
std::string join(const std::vector<std::string>& , const char*);

int checkImage(const char*);
std::array<int,5> getInfoPNG(const char*);

#define SIGNATURE_NUM 8

#endif

[C++] 357 ChatGPTアプリの製作 その42 “libcurlによるHTTP通信”の中断 curl_easy_cleanup 

[Mac M2 Pro 12CPU, Sonoma 14.3.1, clang++ 15.0.0, FLTK 1.3.8]

中断ボタンでlibcurlによるHTTP通信をabortしようとしましたが、かなり手こずりました。

C++では難しいためSwiftへの移植も考えたものの、相当な時間を掛けることになるのでもう一粘りしたところ、あっさり解決しました。

CURL* curl = curl_easy_init();のcurlをグローバル変数にして、中断コールバック関数内でcurl_easy_cleanup(curl);とすれば中断できるようになりました。

シングルスレッドであるFLTKにて送信ボタン押下状態で中断ボタンを押せるようにするにはstd::threadを用い送信コールバック関数(HTTP通信)を別スレッド化する必要があります。

最初は別スレッド化したHTTP通信のプロセスID(PID)をpgrepコマンドで探し、killコマンドで中断しようとしました。しかしstd::threadでは同じプロセスIDをメインスレッドと共用しているため、その方法は使えませんでした。

昨年2023/3/2にChatGPTアプリ開発に着手してから、ずっと抱えていた懸案をようやく解決できました。

libcurlでHTTP通信が容易に中断できない問題はStackOverFlowサイトでも暗礁に乗り上げていたので意外な結末でした。ChatGPTに聞いてもサンプルコードが少ないためか、珍しく迷回答頻発でした。

#include <thread>
#include <future>
#include <curl/curl.h>

extern CURL* curl;

void sendCBWrapper(Fl_Widget* w, void* v) {
    // promiseとfutureを作成
    std::promise<void> p;
    std::future<void> f = p.get_future();
    
    // sendCBを新しいスレッドで実行し、promiseを渡す
    std::thread([w, v, p = std::move(p)]() mutable {
        sendCB(w, v, std::move(p));
    }).detach();
    
    // 別のスレッドでfutureの結果を待機
    std::thread([f = std::move(f)]() mutable {
        f.wait(); // sendCBの終了を待機
        std::system("afplay /System/Library/Sounds/Submarine.aiff"); // システム音を鳴らす
        cout << "sendCB終了" << endl;
    }).detach();
}

void abortCB(Fl_Widget*, void*){
    if (curl){
        curl_easy_cleanup(curl);
        statusBox -> changeColor(YELLOW);
    } else {
        cout << "送信していません" << endl;
    }
}

[C++] 356 ChatGPTアプリの製作 その41 FLTKマルチスレッド化 promise, future

[Mac M2 Pro 12CPU, Sonoma 14.3.1, clang++ 15.0.0, FLTK 1.3.8]

ChatGPTアプリのアップデートは久々です。

cURL通信を中断する機能を実装するため、マルチスレッド対応に着手しました。

まずはリクエストの送信を別スレッドにしてデタッチ(切り離し)するようにしました。

これまでは受信があるまでGUIが固まっていたのが、他のボタンを押したりできるようになります。

ただし別スレッドの動作が終わってもその信号をGUIが受け取ることはできないため、システム音で知らせるようにしました。システム音が聞こえると自分でカーソルを少し動かして、メインスレッドに戻します。メインスレッドに戻るとリクエストの結果がGUIに表示されます。

次は中断ボタンを押すとコールバック関数で受信をabortするようにします。

#include <thread>
#include <future>

void sendCB(Fl_Widget*, void* data, std::promise<void>&& p) {

    <中略>

    p.set_value();
}

void sendCBWrapper(Fl_Widget* w, void* v) {
    // promiseとfutureを作成
    std::promise<void> p;
    std::future<void> f = p.get_future();
    
    // sendCBを新しいスレッドで実行し、promiseを渡す
    std::thread([w, v, p = std::move(p)]() mutable {
        sendCB(w, v, std::move(p));
    }).detach();
    
    // 別のスレッドでfutureの結果を待機
    std::thread([f = std::move(f)]() mutable {
        f.wait(); // sendCBの終了を待機
        std::system("afplay /System/Library/Sounds/Submarine.aiff"); // システム音を鳴らす
        cout << "sendCB終了" << endl;
    }).detach();
}

[Swift] 70 Geminiアプリ製作検討 Google AI SDK for Swift

[Mac M2 Pro 12CPU, Sonoma 14.3.1, Xcode 15.2]

Googleの生成AIモデル Bardの後継モデル Geminiの実力を検証しました。今回はプログラミング補助としての評価です。

結果は散々でした。GPT-4 TurboどころかGPT-3.5の足元にも及ばない、という評価です。

料金が安いので期待していたのですが、とても残念です。あのGoogleですから、それなりのものを出してくると思っていました。

2024年2月時点では、GPT(OpenAI) >>> LLama(Meta)、圏外 Gemini(Google)といったところでしょうか。Geminiは比較以前の問題かと。

OpenAIの天下は当分続きそうです。Appleは完全に周回遅れですから、業務提携か買収しか道はないのでは。

gemini-proを使ったが、回答は0点。これでは厳しい。
GPT-4 Turbo:短いプロンプトでも意図を汲み取って完璧な回答