How to build libarchive on msvc
Claybird edited this page Oct 12, 2019
·
4 revisions
- 方針1:DLLではなく、static linkとする
- 理由:ユーザーにとってDLLが多いのは混乱を招くと考えるため
- 安全にstatic linkするため、VS2017にコンパイラを統一する。Bash On Windowsでクロスコンパイルも可能だが、手間&ランタイムライブラリでややこしくなる。
- 方針2:誰かがビルドしてくれたライブラリ(例えばezwinports)は使用しない
- 理由:セキュリティパッチが出たとき、即座に自力で対応できるようにしたいため
ShiftMediaProjectが各種ライブラリをVCでビルドできるようにして公開してくれているのでありがたく使用する。
プロジェクトフォルダ\SMPにVisual Studio用のソリューションがあるので使用する。 ただし、プロジェクトフォルダ....\msvc*にinclude/lib/licensesをコピーするよう設定されているため、プロジェクトフォルダの場所には注意のこと。
用途 | ライブラリ | ShiftMediaProjectのURL | ライセンス / 備考 |
---|---|---|---|
圧縮解凍 | bzip2 | https://github.com/ShiftMediaProject/bzip2/releases | BSD-style |
文字コード変換 | libiconv | https://github.com/ShiftMediaProject/libiconv/releases | LGPL |
圧縮解凍 | liblzma | https://github.com/ShiftMediaProject/liblzma/releases | public domain |
圧縮解凍 | zlib | https://github.com/ShiftMediaProject/zlib/releases | zlib license |
xml(xar) | libxml2 | https://github.com/ShiftMediaProject/libxml2/releases | MIT License / 先にlibiconvをビルドしておくこと |
多倍長演算 | GMP | https://github.com/ShiftMediaProject/gmp/releases | LGPL / Nettleが依存 |
暗号系 | Nettle | https://github.com/ShiftMediaProject/nettle/releases | LGPL / readme.txtに従ってYASMのインストールが必要。先にGMPをビルドしておくこと。 |
libcharset: LGPL
libiconv付属だが、ShiftMediaProjectのlibiconv付属のものはautogen.shで失敗した。以下の手順で自前ビルドする必要がある。 Bash on Windowsで
- ./autogen.sh
- ./configure そのあと、Visual Studioでソリューションを作成し、以下のファイルを追加。
- localcharset.c
- relocatable-stub.c 追加のインクルードディレクトリは$(ProjectDir);$(ProjectDir)\include LGPL
zstd: BSD License
公式で最新版のWindows Binaryが入手可能だが、念のため自前でビルドする。
- VS2017のコマンドプロンプトを開く
- build\VS_scripts\build.VS2017Community.cmdを実行
lz4: BSD 2-Clause license
公式で最新版のWindows Binaryが入手可能だが、念のため自前でビルドする。 visual/以下にVS用のソリューションファイルあり。
- Expat: libxml2があれば不要(--without-xml2: expat と libxml2 の双方がインストールされている場合に、xar アーカイブフォーマットへのサポートとして、本来なら適切な libxml2 ではなく expat を利用することを指定します。 )
- OpenSSL: Nettleがあれば不要(--without-nettle: OpenSSL と Nettle の双方がインストールされている場合に、暗号化サポートとして、本来なら適切な Nettle ではなく OpenSSL を利用することを指定します。 )
- libb2: libarchiveがリファレンス実装コードを同梱しているので不要
- lzo2: 圧縮解凍用。ライセンスがGPLであり、LhaForgeのライセンス(MITを予定)と整合しないため、採用見送り。
- libeay: OpenSSL関係
- pcre: 正規表現、リストに現れるが不使用
- libgcc: GCCのランタイムライブラリ。GCC不使用なので不要。
"#define HAVE_ICONV 1"を手動で追加しないと、iconvを使用してくれない
最後に、libarchiveをcmakeにかけ、プロジェクトを作らせる
※これでできたライブラリが正常に動作するかどうかは未確認。コンパイルできるところまでしか確認していない。 手動でソリューションを作成しコンパイル。config.hだけはBash on Windowsで作成する。 Bash On Windowsにて
- Makefile.amに「pkgconfigdir = $(libdir)/pkgconfig」を追加
- ./autogen.sh
- ./configure --host=x86_64-w64-mingw32 --enable-static mingwでは改行コードが異なるため、テストスクリプトの結果判定に失敗する。そこでconfigureを編集: 12668行目
- edx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 4`
+ edx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | tr '\r' '\n' | cut -d ":" -f 4`
そのあと、MSVCにて、以下のファイルを含むソリューションを作成。
- config.h
- blake2sp.c
- blake2bp.c
- blake2s.c
- blake2b.c
- blake2-impl.h
- blake2-config.h
- blake2s-round.h
- blake2b-round.h
- blake2s-load-xop.h
- blake2s-load-sse41.h
- blake2s-load-sse2.h
- blake2b-load-sse41.h
- blake2b-load-sse2.h
なお、x86で_mm_set_epi64xが再定義される旨のエラーが出た場合は、そのままコメントアウト。
/*#if defined(_MSC_VER) && !defined(_M_X64)
static inline __m128i _mm_set_epi64x( const uint64_t u1, const uint64_t u0 )
{
return _mm_set_epi32( u1 >> 32, u1, u0 >> 32, u0 );
}
#endif*/
//https://github.com/libarchive/libarchive/wiki/Examples
#define LIBARCHIVE_STATIC
#include <stdio.h>
#include "archive.h"
#include "archive_entry.h"
#include <string>
#include <vector>
#include <assert.h>
#define ASSERT assert
#include <windows.h>
#include <locale.h>
#include <io.h>
#include <fcntl.h>
int main()
{
setlocale(LC_ALL, "");
_setmode(_fileno(stdout), _O_U8TEXT);
struct archive *a;
struct archive_entry *entry;
int r;
a = archive_read_new();
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
r = archive_read_open_filename(a, "z:/test/テスト.zip", 10240);
if (r != ARCHIVE_OK) {
printf("archive not found\n");
return 1;
}
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
const wchar_t* p = archive_entry_pathname_w(entry);
ASSERT(p);
std::wstring name = p;
wprintf(L"%s\n", name.c_str());
archive_read_data_skip(a);
}
archive_read_close(a);
r = archive_read_free(a);
if (r != ARCHIVE_OK) {
printf("Failed to close archive\n");
return 2;
}
return 0;
}