グレインの備忘録

プログラミング関係とかをつらつらと。

Visual StudioのNDK開発でデバッグ時に「ステップできません。このメッセージは間違っているか、転送中に壊れました。」と出る

VisualStudioのNDK開発でデバッグ時にステップ実行をしていると「ステップできません。このメッセージは間違っているか、転送中に壊れました。」と出ることがある。

 

解消できないものかといろいろ試行錯誤していると、どうやら不適切なウォッチ式が存在していることがその原因となっていたようだ。ウォッチ式を全部消したらステップ実行が必ずうまくいった。

 

ステップ実行時に変数情報がうまく取得できないとgdbserver側でSegmentation Faultが発生、プログラムごとハングしてしまうという仕組みだったらしい。

 

やれやれ。

Android NDKでboost::filesystemが使えない

前回(Android NDK r11cでboost 1.61.0をビルド - グレインの備忘録)の続き。

リンクエラーになる

boost::filesystemを使ったアプリをコンパイルするとリンカエラーが出てしまう。

libs/filesystem/src/path.cpp:function (anonymous namespace)::path_locale(): error: undefined reference to 'std::locale::locale(char const*)'


要するにstd::localeのコンストラクタがリンクできていないらしい。
アプリ側で使ってもこんな事にはならないのに一体何故だ・・・

まあ文句を言ってもしょうがないし、とりあえずlocale機能は自分は使っていないと思うので横着して済ませておく。

boostのlibs/filesystem/src/path.cppの908行目あたりの、

# else  // Other POSIX
    // ISO C calls std::locale("") "the locale-specific native environment", and this
    // locale is the default for many POSIX-based operating systems such as Linux.
    return std::locale("");
# endif

ってなってるやつを

# else  // Other POSIX
    // ISO C calls std::locale("") "the locale-specific native environment", and this
    // locale is the default for many POSIX-based operating systems such as Linux.
    #ifdef ANDROID
    return std::locale();
    #else
    return std::locale("");
    #endif
# endif

に変える。

この後boost::filesystemを再ビルドしてもう一回アプリをコンパイルしたらとりあえず通った模様。

NDKでのboostは闇が深い…

Android NDK r11cでboost 1.61.0をビルド

NDKでboost使おうと思ったら結構大変だったのでメモ。

まずビルドのやり方を調べてみて、良さげだったのがこのページ。

c++ - How to compile Boost 1.61 for Android NDK 11 - Stack Overflow

ここの2番目のポストのやり方でほぼ完全にうまくいった。

一応簡単にここにもまとめておく。

ビルド準備

MinGW or Linux環境を想定。
NDKが${NDK_ROOT}に、boostが${BOOST}にあると仮定する。

1. gcc, binutilsを入れておく

例えば、Ubuntuなら

$ sudo apt-get install gcc binutils

とか。

2. ツールチェインを準備する

例えば展開先フォルダを${TOOLCHAIN}とすると、

$ ${NDK_ROOT}/build/tools/make_standalone_toolchain.sh --arch=arm --platform=android-19 --use-llvm --install-dir=${TOOLCHAIN}

でツールチェインをエクスポートできる。 –platformは自分の必要に応じて変える。

3. ビルド設定ファイルを準備する

${BOOST}/android.clang.jam ファイルに以下の内容を記述する。(NDK_ROOTやTOOLCHAINは適宜置き換えること)

import os ;
local AndroidNDKRoot = ${NDK_ROOT} ;
using clang : android
:
${TOOLCHAIN}/bin/clang++
:
<compileflags>-fexceptions
<compileflags>-frtti
<compileflags>-fpic
<compileflags>-ffunction-sections
<compileflags>-funwind-tables
<compileflags>-Wno-psabi
<compileflags>-march=armv7-a
<compileflags>-mfloat-abi=softfp
<compileflags>-mfpu=vfpv3-d16
<compileflags>-fomit-frame-pointer
<compileflags>-fno-strict-aliasing
<compileflags>-finline-limit=64
<compileflags>-I$(AndroidNDKRoot)/platforms/android-21/arch-arm/usr/include
<compileflags>-Wa,--noexecstack
<compileflags>-DANDROID
<compileflags>-D__ANDROID__
<compileflags>-DNDEBUG
<compileflags>-O2
#<compileflags>-g
<compileflags>-I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.9/include
<compileflags>-I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi/include
<architecture>arm
<compileflags>-fvisibility=hidden
<compileflags>-fvisibility-inlines-hidden
<compileflags>-fdata-sections
<cxxflags>-D__arm__
<cxxflags>-D_REENTRANT
<cxxflags>-D_GLIBCXX__PTHREADS
;
4. boostをビルドする

普通にbootstrapからのb2で。

$ cd ${BOOST}
$ ./bootstrap.sh --with-toolset=gcc
$ ./b2 --user-config=android.clang.jam threading=multi link=static \
  runtime-link=static toolset=clang-android target-os=linux \
  threadapi=pthread --stagedir=android

あとはb2のオプションに -j 8とかつけるとマルチスレッドで処理してくれるので速くビルドできるかも。

ただ、コンパイルが通るやつと通らないやつがあるっぽい。一応手元でチェックしてみた結果がこんな感じ。

atomic - success
chrono - success
container - success
context - fail
coroutine - fail
coroutine2 - fail
date_time - success
exception - success
filesystem - success
graph - success
graph_parallel - success
iostreams - fail
locale - success
log - success
math - fail
metaparse - success
mpi - success
program_options - success
python - fail
random - success
regex - success
serialization - success
signals - success
system - success
test - success
thread - success
timer - success
type_erasure - success
wave - success

しかも上のリストでsuccessになってるやつでも本体のリンク時にエラーが起こったりと、結局実際に使ってみないと使えるかどうか分かんないっぽい。。。

バイナリモードのfseekとfwriteの挙動

バイナリファイルで一旦fwriteした後に前方へfseekして、もう一回fwriteすると上書きされるのか挿入されるのかたまに忘れるのでメモっとく。

結論から言うとfseekしてからfwriteすると元のデータは上書きされる。(まあ当たり前か)

例えば、新規ファイルについて

int data = 0x12345678;
fwrite(&data, 4, 1, fp);
fseek(fp, 2, SEEK_SET);
data = 0x90ABCDEF;
fwrite(&data, 4, 1, fp);

みたいにすると、ファイルの中身は

78 56 EF CD AB 90

の6バイトになる。