cmake で bcc582 と vc141 一気にビルド

1本の CMakeLists.txt と数本の短いバッチフィルで、2つのコンパイラ bcc582 と vc141 をそれぞれ使って、さらにそれぞれの debug バージョンと release バージョンを一気にビルドするためのメモです。

今後付け足していく予定です。

ディレクトリ構造

. ; ソース, CMakeLists.txt, バッチファイル, 改名したEXEファイルをコピーしてくる
|
+-- build ; ビルド ディレクトリ
     |
     +-- bcc582d ; bcc582 debug バージョン用 ビルド ディレクトリ
     |
     +-- bcc582 ; bcc582 release バージョン用 ビルド ディレクトリ
     |
     +-- vc141 ; vc141用 ビルド ディレクトリ

環境変数

コンパイラのインストールディレクトリを設定しておく

BCC582=C:\PROGRA~1\Borland\BDS\4.0
VC141=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build

バッチファイル

build.bat

@echo off
cmd /c build_bcc582.bat
cmd /c build_vc141.bat
cp --update --no-target-directory build/bcc582d/foo.exe       ./foo_bcc582d.exe
cp --update --no-target-directory build/bcc582/foo.exe        ./foo_bcc582.exe
cp --update --no-target-directory build/vc141/release/foo.exe ./foo_vc141.exe
cp --update --no-target-directory build/vc141/debug/foo.exe   ./foo_vc141d.exe

build_bcc582.bat

@echo off
PATH=%BCC582%\Bin;%PATH%
mkdir build\bcc582d
cd build\bcc582d
cmake -DCMAKE_BUILD_TYPE=Debug -G "Borland Makefiles" ../..
make
cd ..\..
mkdir build\bcc582
cd build\bcc582
cmake -DCMAKE_BUILD_TYPE=Release -G "Borland Makefiles" ../..
make -DNDEBUG
cd ..\..

build_vc141.bat

@echo off
call "%VC141%\vcvarsall.bat" x86
mkdir build\vc141
cd build\vc141
cmake ../..
for %%a in (*.vcxproj) do msbuild %%a /m /p:Configuration=Debug
for %%a in (*.vcxproj) do msbuild %%a /m /p:Configuration=Release
cd ..\..

CMakeLists.txt

cmake_minimum_required(VERSION 3.11)
project(foo CXX)
add_executable(foo main.cpp)

main.cpp テスト用サンプル

#include <iostream>
int main()
{
    using namespace std;
#ifdef NDEBUG
    cout << "Release(NDEBUG defined)" << endl;
#else
    cout << "DEBUG(NDEBUG not defined)" << endl;
#endif
#ifdef __BORLANDC__
    cout << "BORLANDC: " << hex << __BORLANDC__ << endl;
#endif    
#ifdef _MSC_VER
    cout << "MSC: " << _MSC_VER << endl;
#endif    
    return 0;
}

Windows で ionice

Windows で、ビルド(特にリンク)とかディスクアクセスが多い処理をさせている最中、他の作業をやろうとしてもディスクアクセスが遅くてイライラすることがありませんか?

CPUの優先度を下げるのは start /low や cygwin の nice を使えばできますが、IOの優先度を下げるコマンドは無いみたいです。

Windows Vista から Windows API 関数 SetPriorityClass の2つめの引数にPROCESS_MODE_BACKGROUND_BEGIN, PROCESS_MODE_BACKGROUND_END が追加されています。

以下の挟まれた部分のコードが、低いIO優先度で実行されます。

SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN);
// ... 低いIO優先度で実行される
SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);

これを利用して、I/O優先度を下げてコマンドを実行するコマンドを作ってみました。以下をコンパイルして ionice.exe を作ります。

linux の同じ名前のコマンドのようなオプション引数は対応してません。

一応 VC141 (Visual Studio 2017 の Visual C++) と BCC582 (C++Builder 2006) で確認してあります。

#include <windows.h>
#include <process.h>
#include <iostream>

// 定義がなかったら定義する
#ifndef PROCESS_MODE_BACKGROUND_BEGIN
#define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000
#endif

#ifndef PROCESS_MODE_BACKGROUND_END
#define PROCESS_MODE_BACKGROUND_END 0x00200000
#endif

// _spanvp は BCCだと spanvp 引数・戻り値は同じ
#ifdef __BORLANDC__
#define _spawnvp spawnvp
#endif

int main(int argc, char** argv)
{
    using namespace std;
    if (argc < 2) {             // 引数無し
        cout << "書式: ionice <コマンドライン...>" << endl;
        return 0;
    }
    //
    if (!SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN)) {
        cerr << "SetPriorityClass(*, PROCESS_MODE_BACKGROUND_BEGIN) エラー: " << GetLastError() << endl;
        cerr << "でも続行します" << endl;
    }
    int result = _spawnvp(P_WAIT, argv[1], argv+1);
    if (!SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END)) {
        cerr << "SetPriorityClass(*, PROCESS_MODE_BACKGROUND_END) エラー: " << GetLastError() << endl;
        cerr << "でも続行します" << endl;
    }
    return result;
}

使い方

例1

        make nantoka

を低い IO 優先度で実行したい場合に

        ionice make nantoka

例2

場合によっては(バッチファイルとか?) cmd.exe を噛まさないと動かないかもしれません。

        build nantoka

を低い IO 優先度で実行したい場合に

        ionice cmd /c build nantoka

Emacs で C++ Builder 付属の grep で検索してジャンプ

WindowsGNU Emacs 25.2.1 を使っていますが、cygwin の egrep だと shift-jis の2バイト文字が検索できないので、C++ Builder 付属の grep を使って検索をして、検索結果からジャンプできるようにしてみました。

~/.emacs に以下を入れます。

(load "grep")                           ; grep-regexp-alist が defconst されてるせいか先に読み込まないと上手く変更できない
(setq grep-use-null-device nil)         ; Windows では使わない

;; bcc の grep を使用する
(setq grep-command "grep -o -n -i ")
;; -o は unix っぽい形式(これが無いと解釈できない)
;; -n は行番号付加 (これが無いと解釈できない)
;; -i は大文字小文字区別しない
;; -d はディレクトリを下る

;; bcc の grep の出力も解釈できるように
;;
;; unix grep : <file>:<lineno>:<text>
;; bcc grep -on :
;;   ファイルの最初: <file>:<lineno:%-7d> <text>
;;   それ以外:       <file>  <lineno:%-7d> <text>
;;
(setq bcc-grep-regexp-alist
      '(("^\\(.*?[^/\n]\\)[: ][ \t]*\\([1-9][0-9]*\\)\\([ \t]*:\\)?"
         1 2
         ((lambda ()
            (when grep-highlight-matches
              (let* ((beg (match-end 0))
                     (end (save-excursion (goto-char beg) (line-end-position)))
                     (mbeg (text-property-any beg end 'font-lock-face grep-match-face)))
                (when mbeg
                  (- mbeg beg)))))
          .
          (lambda ()
            (when grep-highlight-matches
              (let* ((beg (match-end 0))
                     (end (save-excursion (goto-char beg) (line-end-position)))
                     (mbeg (text-property-any beg end 'font-lock-face grep-match-face))
                     (mend (and mbeg (next-single-property-change mbeg 'font-lock-face nil end))))
                (when mend
                  (- mend beg)))))))))
(setq grep-regexp-alist bcc-grep-regexp-alist)

ブログスタート

主に C++Windows のソフトウェア開発を行っています。そこで調べたことや気づいたことを書いて行こうと思います。

現在使っているのは Borland C++ Builder 2006、もう12年も前のコンパイラです。フレームワークは OWLNext 6.30.4 で、OWL 2.0 の頃から使ってます。

VC141 (Visual Studio 2017 の Visual C++) + OWLNext 6.44.2 への移行を画策していますが、既存プロジェクトの移植がなかなか進みません。

C++ の他に用があるのは Perl 5 と、あと Emacs Lisp です。

Lisp だとコードをコンパクトに書けるので、エディタのマクロとしてだけでなく、実験用にも使用してます。