ソースツリー外でBodyIoRTCのビルド

Choreonoidの最新版に対応したUbuntuでもWindowsでも使えるKobuki用のモデルの作成しようとしています.そのために,Choreonoidのソースツリーの外でBodyIoRTCのビルドを試みています.Ubuntuではうまくできましたが,Windowsではまだ成功していません.以下に詳細を記しますので,ご助言をいただけると幸いです.

Ubuntuでは,ソースツリーとは独立したディレクトリに,cppファイルと以下のCMakeLists.txtを置いてビルドができ,実行の確認もできました.

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(KobukiIoRTC)

find_package(OpenRTM)
if (WIN32)
  set(Choreonoid_DIR C:/Choreonoid/share/choreonoid/cmake)
endif (WIN32)
find_package(Choreonoid)


if (DEFINED OPENRTM_INCLUDE_DIRS)
  string(REGEX REPLACE "-I" ";"
    OPENRTM_INCLUDE_DIRS "${OPENRTM_INCLUDE_DIRS}")
  string(REGEX REPLACE " ;" ";"
    OPENRTM_INCLUDE_DIRS "${OPENRTM_INCLUDE_DIRS}")
endif (DEFINED OPENRTM_INCLUDE_DIRS)

if (DEFINED OPENRTM_LIBRARY_DIRS)
  string(REGEX REPLACE "-L" ";"
    OPENRTM_LIBRARY_DIRS "${OPENRTM_LIBRARY_DIRS}")
  string(REGEX REPLACE " ;" ";"
    OPENRTM_LIBRARY_DIRS "${OPENRTM_LIBRARY_DIRS}")
endif (DEFINED OPENRTM_LIBRARY_DIRS)

if (DEFINED OPENRTM_LIBRARIES)
  string(REGEX REPLACE "-l" ";"
    OPENRTM_LIBRARIES "${OPENRTM_LIBRARIES}")
  string(REGEX REPLACE " ;" ";"
    OPENRTM_LIBRARIES "${OPENRTM_LIBRARIES}")
endif (DEFINED OPENRTM_LIBRARIES)

include_directories(${OPENRTM_INCLUDE_DIRS})
include_directories(${OMNIORB_INCLUDE_DIRS})
include_directories(${CHOREONOID_INCLUDE_DIRS})
add_definitions(${OPENRTM_DEFINITIONS})
add_definitions(${OMNIORB_CFLAGS})
add_definitions(${CHOREONOID_DEFINITIONS})
link_directories(${OPENRTM_LIBRARY_DIRS})
link_directories(${OMNIORB_LIBRARY_DIRS})
link_directories(${CHOREONOID_LIBRARY_DIRS})

set(CMAKE_CXX_STANDARD 11)

if(MSVC)
  add_compile_options(${OPENRTM_CFLAGS})
  add_definitions(
    -D__WIN32__ -D__x86__ -D__NT__ -D__OSVERSION__=4
    -D_CRT_SECURE_NO_DEPRECATE -D_WIN32_WINNT=0x0500 -DRTC_CORBA_CXXMAPPING11)
endif()

function(add_cnoid_body_io_rtc)
  set(target ${ARGV0})
  list(REMOVE_AT ARGV 0)

  add_library(${target} SHARED ${ARGV})
  target_link_libraries(${target} CnoidBodyIoRTC CnoidBody CnoidUtil ${OPENRTM_LIBRARIES} ${OPENRTM_CAMERA_LIBRARY})
  
  if(MSVC)
    add_compile_options(${OPENRTM_CFLAGS})
  endif()

  set_target_properties(${target} PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CNOID_PLUGIN_SUBDIR}/rtc
    PREFIX "")
  set_target_properties(${target} PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/rtc
    PREFIX "")

  if(ENABLE_INSTALL_RPATH)
    set_target_properties(${target} PROPERTIES INSTALL_RPATH "$ORIGIN/../..")
  endif()

  install(TARGETS ${target}
    RUNTIME DESTINATION ${CNOID_PLUGIN_SUBDIR}/rtc CONFIGURATIONS Release Debug
    LIBRARY DESTINATION ${CNOID_PLUGIN_SUBDIR}/rtc CONFIGURATIONS Release Debug)
endfunction()

add_cnoid_body_io_rtc(KobukiIoRTC KobukiIoRTC.cpp)

CMakeやChoreonoidの理解が十分ではないため,不適切な部分があるかもしれません.ご指摘をいただけると幸いです.

ChoreonoidのCMakeの設定で,WindowsではINSTALL_SDKにチェックが入りませんが,これにチェックを入れてインストールしました.これによって,ヘッダファイルの問題は解決できましたが,リンクと実行に問題があります.

  • target_link_libraries()CnoidBody CnoidUtil ${OPENRTM_LIBRARIES}を追加する必要がありました.Ubuntuでこれなしでリンクが通るのが不思議です.

  • インストールディレクトリにCnoidBodyIoRTC.lib CnoidBody.lib CnoidUtil.libがありません(Windoiwsではdllを使う場合でもlibが必要なのですよね?).CMakeでどのように解決すればいいのかわからなかったので,まずは,それらのファイルをビルドディレクトリのlibからインストールディレクトリのlibへ手作業でコピーしました.

  • プロジェクトファイルで指定するBodyIoRTCのモジュールのパスをUbuntuとWindowsで統一したいのですが,set_target_properties()LIBRARY_OUTPUT_DIRECTORYLIBRARY_OUTPUT_DIRECTORY_RELEASEを設定しても,反映されません.dllファイルを手作業でbuild/rtcへコピーしたところ,Ubuntuと共通のプロジェクトファイルで動作することは確認しました.

以上です.よろしくお願いいたします.

開発者の皆様,

質問の仕方が適切ではないかもしれませんが,本件についてもフォローしていただけると助かります(こちらも卒研がかかっています).

以下のドキュメントに書いてあるのですが、

https://cmake.org/cmake/help/v3.12/command/install.html

Windowsの場合、DLLはLIBRARYターゲットではなくRUNTIMEターゲットとして扱われるらしいので、そこが悪さをしているかもしれません。

set_target_properties() では LIBRARY_OUTPUT_DIRECTORYLIBRARY_OUTPUT_DIRECTORY_RELEASE ではなく、 RUNTIME_OUTPUT_DIRECTORYRUNTIME_OUTPUT_DIRECTORY_RELEASE を設定する必要があるかもしれません。

普段、Windowsはあまり使わないので、はずしていたらすいません。

SDKの問題に関しては、Windowsの場合は、libファイルはARCHIVEターゲットとして扱われるらしいので、現在のChoreonoid側のcmakeの設定から漏れてしまっているのかもしれませんね。

@nakaoka さん

SDKのインストールの問題に関しては、ここを修正する必要があるかもしれません。

INSTALL_SDKが指定された場合はSTATIC_LIBRARYでない場合でもARCHIVEターゲットも追加する必要がありそうです。

返信おそくなりまして申し訳ありません。

  • インストールディレクトリに CnoidBodyIoRTC.lib CnoidBody.lib CnoidUtil.lib がありません

こちらに関しては、 ご指摘の通りですので修正しておきます。

  • プロジェクトファイルで指定するBodyIoRTCのモジュールのパスをUbuntuとWindowsで統一したいのですが, set_target_properties()LIBRARY_OUTPUT_DIRECTORYLIBRARY_OUTPUT_DIRECTORY_RELEASE を設定しても,反映されません.

    こちらは、

install(TARGETS ${target}
RUNTIME DESTINATION ${CNOID_PLUGIN_SUBDIR}/rtc CONFIGURATIONS Release Debug
LIBRARY DESTINATION ${CNOID_PLUGIN_SUBDIR}/rtc CONFIGURATIONS Release Debug)

の行の ${CNOID_PLUGIN_SUBDIR}をインストールしたい場所に変更してINSTALLでビルドすればその場所にコピーされます。${CHOREONOID_PLUGIN_DIR}にすれば、choreonoidのインストール先になります。試してみてください。

  • target_link_libraries()CnoidBody CnoidUtil ${OPENRTM_LIBRARIES} を追加する必要がありました.Ubuntuでこれなしでリンクが通るのが不思議です.

こちらに関しては、自信がないのでリンカーの動作に詳しい方に解説お願いします。

リンカの問題に関しては以下の部分でRTC_CORBA_CXXMAPPING11が有効化されているのがちょっと気になりますね。

Choreonoid側ではRTC_CORBA_CXXMAPPING11なしでコンパイルされていると思うので、このオプションを有効化したときに必要なシンボルがChoreonoidに含まれていない可能性もあるのかな、と思いました。

リンカの出力するシンボル未解決エラーのログが見られれば、もう少し深いことがわかりそうですが。

これは,sample/OpenRTM/CMakeLists.txt の内容をそのままコピーしたものです.本来の意図はわかりません.

RTC_CORBA_CXXMAPPING11は、下記のCORBAのC++11マッピングを有効にするフラグです。

https://www.omg.org/news/meetings/workshops/RT-2012-presentations/02-S4-03_Willemsen.pdf

std::stringやstd::vectorなどが使えるようになるので、いつも知らないうちに使っている状態と思います。

OpenRTM側を見てみたのですが、omniORBのバージョン4.1以上を使っている場合であれば自動で有効化されるようです。
http://svn.openrtm.org/OpenRTM-aist/trunk/OpenRTM-aist/configure.ac

ただ、サンプルであえて有効化しているということは、WindowsでコンパイルしたOpenRTMでomniORBのバージョン検出の不整合があった時期があった(今も?)ということですかね?
もし今も不整合が続いていたとした場合、Choreonoid側も同じオプションを付けてコンパイルしないと、ライブラリに必要なシンボルが含まれない形になるかもしれません。

ただ、これが原因ではない可能性もあります。コンパイル&リンク時のエラーログが見られれば、もう少し詳しいことがわかります。

yosukeさん、 hattorishizukoさん、ご回答いただきありがとうございます。
すみません、しばらく立て込んでいて回答できませんでした。

まず、INSTALL_SDKに関しては、修正版をgithubにpushしておきました。

target_link_libraries()CnoidBody CnoidUtil ${OPENRTM_LIBRARIES} を追加する必要がありました.Ubuntuでこれなしでリンクが通るのが不思議です.

これについては、UbuntuというかLinuxでは、リンカへのオプションにもよりますが、確かデフォルトでは、ビルドにおけるリンク時に全てのシンボルが無くてもリンクは通るようになっています。その場合、実行時に何らかの手段で必要な共有ライブラリ(.soファイル)が読み込まれていれば、実行もできます。読み込まれていなければ実行時にエラーになります。

この挙動は、Choreonoid本体のCMakeで CHECK_UNRESOLVED_SYMBOLS というオプションをONにすることで変えられます。ONにすると、リンク時に必要なシンボルが全て揃っているかのチェックをするようになり、ない場合は警告がでるようになります。(ただ、警告は出るけどビルド自体はできたような気がします。)これをONにして、target_link_librariesの記述も無しの場合は、警告がでるかと思います。

Windows(VC++)の場合は、ビルド時のリンクにおいて必要なシンボルが全て無いとダメなのだと思います。

RTC_CORBA_CXXMAPPING11 については、このオプションを付けるようになった経緯について、あまり記憶が無く、分かりませんでした。本体とサンプルでオプションが異なるというのはよくないですね。今後のチェック事項に入れておこうと思います。