ククログ

株式会社クリアコード > ククログ > 公式のWindows版PostgreSQLパッケージ用の拡張機能のビルドシステムの作り方

公式のWindows版PostgreSQLパッケージ用の拡張機能のビルドシステムの作り方

PostgreSQLは各種プラットフォーム用のパッケージを提供しているため、簡単にインストールすることができます。PostgreSQL用の拡張機能のインストール方法も簡単です。拡張機能のバイナリーと設定ファイル1を拡張機能用のディレクトリーに配置してCREATE EXTENSIONを実行するだけです。

GNU MakeがあるシステムではPGXS2という拡張機能のビルドを支援する仕組みを使うことができます。PGXSを使えば数十行程度でGCCを使って拡張機能をビルドする仕組みができます3

しかし、公式のWindows版PostgreSQLパッケージ4はVisual Studioでビルドされているため、GCCを使うPGXSでは公式のWindows版PostgreSQLパッケージ用の拡張機能をビルドできません。そこで、CMakeを使って公式のWindows版PostgreSQLパッケージ用のビルドシステムの作り方を紹介します。

なお、MinGWを使ってWindows版PostgreSQLをビルドする場合はPGXSを使えます5。また、PostgreSQL本体と一緒に拡張機能をビルドする場合はPostgreSQL自体のビルドシステムを使えます6。ここで紹介する方法は「公式のWindows版PostgreSQLパッケージ用に拡張機能だけをビルドする」ビルドシステムの作り方です。

公式のWindows版PostgreSQLパッケージ用拡張機能のビルド方法

ビルドシステムを作るためにはビルド方法を確立していなければいけません。Visual Studio用の拡張機能のビルド方法はPostgreSQLのWikiにまとまっています。ざっくり言うと次の設定をしたVisual Studioのソリューションファイルを作ってビルドします。

  • DLLを作成する
  • 素のCとしてコンパイルする
  • C++の例外を無効にする
  • includeの検索パスに↓を追加する
    • include\server\port\win32_msvc
    • include\server\port\win32
    • include\server
    • include
  • ライブラリーの検索パスに↓を追加する
    • lib
  • postgres.libをリンクする

Wikiではこれらの設定をしたプロジェクトファイルを手動で作る前提になっているように見えますが、バージョン管理システムと相性が悪いですし、更新にはVisual Studioが必要になりメンテナンスしづらいのでやりたくありません。ということで、これらの設定をしたVisual Studioでのビルド用のファイルを生成することにします7

CMakeを使った公式のWindows版PostgreSQLパッケージ用拡張機能のビルドシステムの使い方

CMakeを使うとVisual Studioでのビルド用のファイルを生成することができます。また、CMakeはCPackというパッケージ作成用の仕組みも用意しているのでビルド済みの拡張機能のパッケージ作成までできます。

CMakeを使った場合は次のようにすればビルドできます。「%PostgreSQLをインストールしたフォルダー%」と「%PostgreSQLのバージョン%」は適切な値に置き換えます。例えば、「..\pgsql」と「9.4.1-3」といった具合です。

> cmake . -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=%PostgreSQLをインストールしたフォルダー% -DPOSTGRESQL_VERSION=%PostgreSQLのバージョン%
> cmake --build . --config Release

ビルドした拡張機能をインストールする場合は次のようにします。

> cmake --build . --config Release --target install

パッケージを作成する場合は次のようにします。

> cmake --build . --config Release --target package

簡単ですね。

CMakeを使った公式のWindows版PostgreSQLパッケージ用拡張機能のビルドシステム

ではCMake用の設定ファイル(CMakeLists.txt)を作ります。ベースは次のようになります。ここに前述のVisual Studioでの設定を追加していきます。

cmake_minimum_required(VERSION 3.0.0)

set(PROJECT_NAME "拡張機能名") # 例: "PGroonga"
set(PROJECT_ID "拡張機能のID") # 例: "pgroonga"

set(VENDOR "拡張機能の開発者") # 例: "The PGroonga Project"

set(VERSION_MAJOR "拡張機能のメジャーバージョン") # 例: "0"
set(VERSION_MINOR "拡張機能のマイナーバージョン") # 例: "5"
set(VERSION_PATCH "拡張機能のパッチバージョン")   # 例: "0"
# ↑は.controlから抽出することもできる
# 方法は後述するPGroongaの例を参照すること
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")

project("${PROJECT_ID}")

# ↓はユーザーが指定した「%PostgreSQLをインストールしたフォルダー%」になる
set(POSTGRESQL_DIR "${CMAKE_INSTALL_PREFIX}"
  CACHE PATH "PostgreSQL binary directory")
# ↓はパッケージを作成するときだけ必要
set(POSTGRESQL_VERSION "unknown"
  CACHE STRING "PostgreSQL version")

set(LIBRARY_NAME "lib${PROJECT_ID}")

set(EXTENSION_DIR "lib")
set(EXTENSION_DATA_DIR "share/extension")
set(DOCUMENT_DIR "share/${PROJECT_ID}")

set(SOURCES
  "ソースコード1.c"
  "ソースコード2.c"
  "...")

Visual Studioでの設定を再確認します。

  • DLLを作成する
  • 素のCとしてコンパイルする
  • C++の例外を無効にする
  • includeの検索パスに↓を追加する
    • include\server\port\win32_msvc
    • include\server\port\win32
    • include\server
    • include
  • ライブラリーの検索パスに↓を追加する
    • lib
  • postgres.libをリンクする

順に設定します。まずは「DLLを作成する」です。SHAREDとファイル名のベース名を拡張機能IDにすることがポイントです。

add_library("${LIBRARY_NAME}" SHARED ${SOURCES})
set_target_properties("${LIBRARY_NAME}"
   PROPERTIES
   OUTPUT_NAME "${PROJECT_ID}")

次は「素のCとしてコンパイルする」ですが、これは特になにもする必要はありません。

続いて「C++の例外を無効にする」は/EHscオプションを指定します。詳細はMSDNの/EH(例外処理モデル)のドキュメントを参考にしてください。

set_source_files_properties(${SOURCES}
  PROPERTIES
  COMPILE_FLAGS "/EHsc")

「includeの検索パスを追加する」は次のようにします。

include_directories(
  "${POSTGRESQL_DIR}/include/server/port/win32_msvc"
  "${POSTGRESQL_DIR}/include/server/port/win32"
  "${POSTGRESQL_DIR}/include/server"
  "${POSTGRESQL_DIR}/include")

「ライブラリーの検索パスを追加する」は次のようにします。

link_directories(
  "${POSTGRESQL_DIR}/lib")

postgres.libをリンクする」は次のようにします。

target_link_libraries("${LIBRARY_NAME}"
  "postgres.lib")

これで必要な設定が完了しました。簡単ですね。後はインストール先の指定とパッケージ作成用の設定だけです。

インストール先の指定は次のようになります。

install(TARGETS "${LIBRARY_NAME}"
  DESTINATION "${EXTENSION_DIR}")

install(FILES
  "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.control"
  DESTINATION "${EXTENSION_DATA_DIR}")

install(FILES
  "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.sql"
  RENAME "${PGRN_PROJECT_ID}--${VERSION_FULL}.sql"
  DESTINATION "${PGRN_EXTENSION_DATA_DIR}")

パッケージ作成用の設定は次の通りです。すでに設定した値を使っているだけです。

set(CPACK_GENERATOR "ZIP")
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}")
set(CPACK_PACKAGE_VENDOR "${VENDOR}")
if(CMAKE_CL_64)
  set(PACKAGE_SYSTEM_NAME "x64")
else()
  set(PACKAGE_SYSTEM_NAME "x86")
endif()
set(CPACK_PACKAGE_FILE_NAME
  "${PROJECT_ID}-${VERSION_FULL}-postgresql-${POSTGRESQL_VERSION}-${PACKAGE_SYSTEM_NAME}")

include(CPack)

まとめると次の通りです。

cmake_minimum_required(VERSION 3.0.0)

set(PROJECT_NAME "拡張機能名") # 例: "PGroonga"
set(PROJECT_ID "拡張機能のID") # 例: "pgroonga"

set(VENDOR "拡張機能の開発者") # 例: "The PGroonga Project"

set(VERSION_MAJOR "拡張機能のメジャーバージョン") # 例: "0"
set(VERSION_MINOR "拡張機能のマイナーバージョン") # 例: "5"
set(VERSION_PATCH "拡張機能のパッチバージョン")   # 例: "0"
# ↑は.controlから抽出することもできる
# 方法は後述するPGroongaの例を参照すること
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")

project("${PROJECT_ID}")

# ↓はユーザーが指定した「%PostgreSQLをインストールしたフォルダー%」になる
set(POSTGRESQL_DIR "${CMAKE_INSTALL_PREFIX}"
  CACHE PATH "PostgreSQL binary directory")
# ↓はパッケージを作成するときだけ必要
set(POSTGRESQL_VERSION "unknown"
  CACHE STRING "PostgreSQL version")

set(LIBRARY_NAME "lib${PROJECT_ID}")

set(EXTENSION_DIR "lib")
set(EXTENSION_DATA_DIR "share/extension")
set(DOCUMENT_DIR "share/${PROJECT_ID}")

set(SOURCES
  "ソースコード1.c"
  "ソースコード2.c"
  "...")

add_library("${LIBRARY_NAME}" SHARED ${SOURCES})
set_target_properties("${LIBRARY_NAME}"
   PROPERTIES
   OUTPUT_NAME "${PROJECT_ID}")

set_source_files_properties(${SOURCES}
  PROPERTIES
  COMPILE_FLAGS "/EHsc")

include_directories(
  "${POSTGRESQL_DIR}/include/server/port/win32_msvc"
  "${POSTGRESQL_DIR}/include/server/port/win32"
  "${POSTGRESQL_DIR}/include/server"
  "${POSTGRESQL_DIR}/include")

link_directories(
  "${POSTGRESQL_DIR}/lib")

target_link_libraries("${LIBRARY_NAME}"
  "postgres.lib")

install(TARGETS "${LIBRARY_NAME}"
  DESTINATION "${EXTENSION_DIR}")

install(FILES
  "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.control"
  DESTINATION "${EXTENSION_DATA_DIR}")

install(FILES
  "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.sql"
  RENAME "${PGRN_PROJECT_ID}--${VERSION_FULL}.sql"
  DESTINATION "${PGRN_EXTENSION_DATA_DIR}")

set(CPACK_GENERATOR "ZIP")
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}")
set(CPACK_PACKAGE_VENDOR "${VENDOR}")
if(CMAKE_CL_64)
  set(PACKAGE_SYSTEM_NAME "x64")
else()
  set(PACKAGE_SYSTEM_NAME "x86")
endif()
set(CPACK_PACKAGE_FILE_NAME
  "${PROJECT_ID}-${VERSION_FULL}-postgresql-${POSTGRESQL_VERSION}-${PACKAGE_SYSTEM_NAME}")

include(CPack)

実際に使われているCMakeの設定ファイルはPGroongaのCMakeLists.txtを参考にするとよいでしょう。

また、実際に作成したパッケージはhttp://packages.groonga.org/windows/pgroonga/以下にあります。こちらもあわせて参考にしてください。

まとめ

公式のWindows版PostgreSQLパッケージ用の拡張機能のビルドシステムの作り方を紹介しました。ここで紹介した方法はCMakeを使っています。Visual StudioでビルドしなければいけないときにCMakeは便利なので、そんなときはCMakeを思い出してみてください。

  1. 拡張機能のメタデータを書いた.controlファイルと拡張機能のインストール方法を書いた.sqlファイル。

  2. なんの略かわかりませんが、PostgreSQL Extension Systemの略な気はします。

  3. ただし、.deb.rpmなどパッケージを作る仕組みは提供していません。それらは自分で作る必要があります。PGroongaが使っている仕組みが参考になるかもしれません。

  4. EnterpriseDBが提供していますが、これは公式のパッケージなんですよ…ね?

  5. PGXSの中身を見ると使えるように見えます。

  6. ソースを見ると使えるように見えます。

  7. PostgreSQL自体のビルドシステムもこのアプローチのように見えます。