反復解法ライブラリLisのWindows 64bit対応化

国産の有名なライブラリである反復解法ライブラリLisをWindowsアプリケーションで使用した際に躓いたのでメモ。
http://www.ssisc.org/lis/index.ja.html

以下の環境でWindows版のLisをコンパイルして使用すると、メモリのアクセス違反が頻発して使い物になりませんでした。以下、アプリのコンパイル環境です。

  • 自作アプリケーションはFortran
  • integerは4 byte、realは8 byteをkindで定義して使用
  • assume:underscoreとnames:lowercaseを使用
  • MPIやOpenMPは使用しない

この状態でLisを同じプロジェクトに組み込み、依存関係を設定してコンパイルすると、コンパイルは通りますが、実行途中で止まります。試行錯誤の途中でエラーの内容は色々ましたが、create_matrixやsolve_matrixなど様々なところで止まります。

原因は、これ。
http://d.hatena.ne.jp/kohtani/20061225/p1

LinuxはLP64でありlong型が64bitなのに対し、WindowsLLP64を採用していてlong型は32bitになっている。Lisの中でlongが使用されているので、Linuxの64bitで動作しているものがそのままWindows64bitで使用できないことになる。

解決方法としては、必ず64bitになるlong long型を使用すればいい。ただし、long long型は32bitマシンでも64bit整数としてみなされるため、整数型をOSのbitに合わせるためには、マクロを用いなければならない。非常に面倒である。誰だこんな仕様にしたのは。

というわけで、試行錯誤しながらLisをWindows64bit対応にしてみた。

Linux上やWindowコンソール上でconfigureをやる場合に、--enable-fortranと--enable-intelを付けているという想定。

LisをVisual Studio上でコンパイルする場合は、C, C++のコードと、Fortranのコードを別プロジェクトとして登録する必要がある。FortranはVisual Fortranが入っている前提。Fortranのプロジェクトの依存関係で、C, C++のプロジェクトを指定してあげる。
Visual Studioのプロパティから、プリプロセッサの設定のところを開く。「プリプロセッサー定義」のところに、USE_FORTRANとHAVE_CONFIG_WIN_Hを追加する。
USE_FORTRAN定義は、そのままFortranのコードを生成するためのフラグ。
HAVE_CONFIG_WIN_Hは、windows用のヘッダーを読み込むためのフラグ。
もしここにWIN32という定義があれば消す必要がある。WIN32が付いているとWindows用の分岐とともに、32bit用のコード書き換えが起きてしまう。Windows用の書き換えはそんなに難しくないので、手動でやってしまおう。時間計測のヘッダーが違う。それだけ。

具体的なソースコードの書き換えを以下で説明する。

// lis_config_win.h 15行目
//#define USE_QUAD_PRECISION 1 // コメントアウト
// lis_fortran.h 31行目
// long型をlong long型に変更
typedef long long		LIS_MATRIX_F;
typedef long long		LIS_VECTOR_F;
typedef long long		LIS_SOLVER_F;
typedef long long		LIS_ESOLVER_F;
typedef long long		LIS_SCALAR_F;

// 44行目 long long型に変更
#define LIS_V2P(a)	(*(long long *)(a))
#define LIS_P2V(a)	((long long)(a))
// lis_times.c 47行目
	//#include <sys/time.h> // これをコメントアウト
	#include <windows.h> // 追加

以上の変更を行ってからコンパイルすると上手くいきました。
lis_config.hのSIZEOF_を色々いじってみたけど、あんまりソースコードから呼び出されてないので意味が無いようです。SIZEOF_VOID_Pは8になっていると勝手にintegerが64bit精度になってしまったりしてcとfortranの繋ぎでエラーになってしまいます。

補足

ちなみに、私のアプリケーションはFortranの関数名呼び出しに、assume:underscoreとnames:lowercaseを用いていたので、小文字+_という関数名が必要となる。だが、Lisの標準では大文字でアンダースコア無しの関数渡し方法を採用しているのでその辺を変更する必要がある。

// lis_config_win.h
// 6行目
#define F77_FUNC(name,NAME) name // 小文字に変更
// 9行目
#define F77_FUNC_(name,NAME) name // 小文字に変更
// lis_fortran.h 49行目から187行目にかけて
// 全ての関数にアンダースコアを追加する(これよりもっといい方法があるかも)
/**************/
/* MATRIX     */
/**************/
#define lis_matrix_create_f F77_FUNC_(lis_matrix_create_f_, LIS_MATRIX_CREATE_F) 
#define lis_matrix_duplicate_f F77_FUNC_(lis_matrix_duplicate_f_, LIS_MATRIX_DUPLICATE_F) 
#define lis_matrix_destroy_f F77_FUNC_(lis_matrix_destroy_f_, LIS_MATRIX_DESTROY_F) 
#define lis_matrix_set_size_f F77_FUNC_(lis_matrix_set_size_f_, LIS_MATRIX_SET_SIZE_F) 
#define lis_matrix_get_size_f F77_FUNC_(lis_matrix_get_size_f_, LIS_MATRIX_GET_SIZE_F) 
#define lis_matrix_get_range_f F77_FUNC_(lis_matrix_get_range_f_, LIS_MATRIX_GET_RANGE_F) 
#define lis_matrix_set_value_f F77_FUNC_(lis_matrix_set_value_f_, LIS_MATRIX_SET_VALUE_F) 
#define lis_matrix_get_type_f F77_FUNC_(lis_matrix_get_type_f_, LIS_MATRIX_GET_TYPE_F) 
#define lis_matrix_set_type_f F77_FUNC_(lis_matrix_set_type_f_, LIS_MATRIX_SET_TYPE_F)
#define lis_matrix_set_csr_f F77_FUNC_(lis_matrix_set_csr_f_, LIS_MATRIX_SET_CSR_F)
#define lis_matrix_set_csc_f F77_FUNC_(lis_matrix_set_csc_f_, LIS_MATRIX_SET_CSC_F)
#define lis_matrix_set_msr_f F77_FUNC_(lis_matrix_set_msr_f_, LIS_MATRIX_SET_MSR_F)
#define lis_matrix_set_dia_f F77_FUNC_(lis_matrix_set_dia_f_, LIS_MATRIX_SET_DIA_F)
#define lis_matrix_set_ell_f F77_FUNC_(lis_matrix_set_ell_f_, LIS_MATRIX_SET_ELL_F)
#define lis_matrix_set_jad_f F77_FUNC_(lis_matrix_set_jad_f_, LIS_MATRIX_SET_JAD_F)
#define lis_matrix_set_bsr_f F77_FUNC_(lis_matrix_set_bsr_f_, LIS_MATRIX_SET_BSR_F)
#define lis_matrix_set_bsc_f F77_FUNC_(lis_matrix_set_bsc_f_, LIS_MATRIX_SET_BSC_F)
#define lis_matrix_set_coo_f F77_FUNC_(lis_matrix_set_coo_f_, LIS_MATRIX_SET_COO_F)
#define lis_matrix_set_dns_f F77_FUNC_(lis_matrix_set_dns_f_, LIS_MATRIX_SET_DNS_F)
#define lis_matrix_set_vbr_f F77_FUNC_(lis_matrix_set_vbr_f_, LIS_MATRIX_SET_VBR_F)
#define lis_matrix_assemble_f F77_FUNC_(lis_matrix_assemble_f_, LIS_MATRIX_ASSEMBLE_F) 
#define lis_matrix_is_assembled_f F77_FUNC_(lis_matrix_is_assembled_f_, LIS_MATRIX_IS_ASSEMBLED_F) 
#define lis_matrix_malloc_f F77_FUNC_(lis_matrix_malloc_f_, LIS_MATRIX_MALLOC_F)
#define lis_matrix_malloc_csr_f F77_FUNC_(lis_matrix_malloc_csr_f_, LIS_MATRIX_MALLOC_CSR_F)
#define lis_matrix_malloc_csc_f F77_FUNC_(lis_matrix_malloc_csc_f_, LIS_MATRIX_MALLOC_CSC_F)
#define lis_matrix_malloc_bsr_f F77_FUNC_(lis_matrix_malloc_bsr_f_, LIS_MATRIX_MALLOC_BSR_F)
#define lis_matrix_malloc_msr_f F77_FUNC_(lis_matrix_malloc_msr_f_, LIS_MATRIX_MALLOC_MSR_F)
#define lis_matrix_malloc_ell_f F77_FUNC_(lis_matrix_malloc_ell_f_, LIS_MATRIX_MALLOC_ELL_F)
#define lis_matrix_malloc_jad_f F77_FUNC_(lis_matrix_malloc_jad_f_, LIS_MATRIX_MALLOC_JAD_F)
#define lis_matrix_malloc_dia_f F77_FUNC_(lis_matrix_malloc_dia_f_, LIS_MATRIX_MALLOC_DIA_F)
#define lis_matrix_malloc_bsc_f F77_FUNC_(lis_matrix_malloc_bsc_f_, LIS_MATRIX_MALLOC_BSC_F)
#define lis_matrix_malloc_vbr_f F77_FUNC_(lis_matrix_malloc_vbr_f_, LIS_MATRIX_MALLOC_VBR_F)
#define lis_matrix_malloc_coo_f F77_FUNC_(lis_matrix_malloc_coo_f_, LIS_MATRIX_MALLOC_COO_F)
#define lis_matrix_malloc_dns_f F77_FUNC_(lis_matrix_malloc_dns_f_, LIS_MATRIX_MALLOC_DNS_F)
#define lis_matrix_convert_f F77_FUNC_(lis_matrix_convert_f_, LIS_MATRIX_CONVERT_F)
#define lis_matrix_copy_f F77_FUNC_(lis_matrix_copy_f_, LIS_MATRIX_COPY_F)
#define lis_matrix_scaling_f F77_FUNC_(lis_matrix_scaling_f_, LIS_MATRIX_SCALING_F)
#define lis_matrix_get_diagonal_f F77_FUNC_(lis_matrix_get_diagonal_f_, LIS_MATRIX_GET_DIAGONAL_F)
#define lis_matrix_set_blocksize_f F77_FUNC_(lis_matrix_set_blocksize_f_, LIS_MATRIX_SET_BLOCKSIZE_F)


/**************/
/* VECTOR     */
/**************/
#define lis_vector_create_f F77_FUNC_(lis_vector_create_f_, LIS_VECTOR_CREATE_F) 
#define lis_vector_duplicate_f F77_FUNC_(lis_vector_duplicate_f_, LIS_VECTOR_DUPLICATE_F) 
#define lis_vector_destroy_f F77_FUNC_(lis_vector_destroy_f_, LIS_VECTOR_DESTROY_F) 
#define lis_vector_set_size_f F77_FUNC_(lis_vector_set_size_f_, LIS_VECTOR_SET_SIZE_F) 
#define lis_vector_get_size_f F77_FUNC_(lis_vector_get_size_f_, LIS_VECTOR_GET_SIZE_F) 
#define lis_vector_get_range_f F77_FUNC_(lis_vector_get_range_f_, LIS_VECTOR_GET_RANGE_F) 
#define lis_vector_set_value_f F77_FUNC_(lis_vector_set_value_f_, LIS_VECTOR_SET_VALUE_F) 
#define lis_vector_set_values_f F77_FUNC_(lis_vector_set_values_f_, LIS_VECTOR_SET_VALUES_F) 
#define lis_vector_set_values2_f F77_FUNC_(lis_vector_set_values2_f_, LIS_VECTOR_SET_VALUES2_F) 
#define lis_vector_get_value_f F77_FUNC_(lis_vector_get_value_f_, LIS_VECTOR_GET_VALUE_F) 
#define lis_vector_get_values_f F77_FUNC_(lis_vector_get_values_f_, LIS_VECTOR_GET_VALUES_F) 
#define lis_vector_scatter_f F77_FUNC_(lis_vector_scatter_f_, LIS_VECTOR_SCATTER_F) 
#define lis_vector_gather_f F77_FUNC_(lis_vector_gather_f_, LIS_VECTOR_GATHER_F) 
#define lis_vector_print_f F77_FUNC_(lis_vector_print_f_, LIS_VECTOR_PRINT_F) 
#define lis_vector_set_all_f F77_FUNC_(lis_vector_set_all_f_, LIS_VECTOR_SET_ALL_F) 
#define lis_vector_axpy_f F77_FUNC_(lis_vector_axpy_f_, LIS_VECTOR_AXPY_F) 
#define lis_vector_xpay_f F77_FUNC_(lis_vector_xpay_f_, LIS_VECTOR_XPAY_F) 
#define lis_vector_axpyz_f F77_FUNC_(lis_vector_axpyz_f_, LIS_VECTOR_AXPYZ_F) 
#define lis_vector_copy_f F77_FUNC_(lis_vector_copy_f_, LIS_VECTOR_COPY_F) 
#define lis_vector_scale_f F77_FUNC_(lis_vector_scale_f_, LIS_VECTOR_SCALE_F) 
#define lis_vector_pmul_f F77_FUNC_(lis_vector_pmul_f_, LIS_VECTOR_PMUL_F) 
#define lis_vector_pdiv_f F77_FUNC_(lis_vector_pdiv_f_, LIS_VECTOR_PDIV_F) 
#define lis_vector_abs_f F77_FUNC_(lis_vector_abs_f_, LIS_VECTOR_ABS_F) 
#define lis_vector_reciprocal_f F77_FUNC_(lis_vector_reciprocal_f_, LIS_VECTOR_RECIPROCAL_F) 
#define lis_vector_shift_f F77_FUNC_(lis_vector_shift_f_, LIS_VECTOR_SHIFT_F) 
#define lis_vector_dot_f F77_FUNC_(lis_vector_dot_f_, LIS_VECTOR_DOT_F) 
#define lis_vector_nrm1_f F77_FUNC_(lis_vector_nrm1_f_, LIS_VECTOR_NRM1_F) 
#define lis_vector_nrm2_f F77_FUNC_(lis_vector_nrm2_f_, LIS_VECTOR_NRM2_F) 
#define lis_vector_nrmi_f F77_FUNC_(lis_vector_nrmi_f_, LIS_VECTOR_NRMI_F) 
#define lis_vector_sum_f F77_FUNC_(lis_vector_sum_f_, LIS_VECTOR_SUM_F) 
#define lis_vector_is_null_f F77_FUNC_(lis_vector_is_null_f_, LIS_VECTOR_IS_NULL_F) 
/**************/
/* SOLVER     */
/**************/
#define lis_solver_create_f F77_FUNC_(lis_solver_create_f_, LIS_SOLVER_CREATE_F) 
#define lis_solver_destroy_f F77_FUNC_(lis_solver_destroy_f_, LIS_SOLVER_DESTROY_F) 
#define lis_solve_f F77_FUNC_(lis_solve_f_, LIS_SOLVE_F) 
#define lis_solver_set_option_f F77_FUNC_(lis_solver_set_option_f_, LIS_SOLVER_SET_OPTION_F) 
#define lis_solver_get_iters_f F77_FUNC_(lis_solver_get_iters_f_, LIS_SOLVER_GET_ITERS_F) 
#define lis_solver_get_itersex_f F77_FUNC_(lis_solver_get_itersex_f_, LIS_SOLVER_GET_ITERSEX_F) 
#define lis_solver_get_time_f F77_FUNC_(lis_solver_get_time_f_, LIS_SOLVER_GET_TIME_F) 
#define lis_solver_get_timeex_f F77_FUNC_(lis_solver_get_timeex_f_, LIS_SOLVER_GET_TIMEEX_F) 
#define lis_solver_get_residualnorm_f F77_FUNC_(lis_solver_get_residualnorm_f_, LIS_SOLVER_GET_RESIDUALNORM_F) 
#define lis_solver_get_rhistory_f F77_FUNC_(lis_solver_get_rhistory_f_, LIS_SOLVER_GET_RHISTORY_F) 
#define lis_solver_get_solver_f F77_FUNC_(lis_solver_get_solver_f_, LIS_SOLVER_GET_SOLVER_F) 
#define lis_solver_get_precon_f F77_FUNC_(lis_solver_get_precon_f_, LIS_SOLVER_GET_PRECON_F) 
#define lis_solver_get_solvername_f F77_FUNC_(lis_solver_get_solvername_f_, LIS_SOLVER_GET_SOLVERNAME_F) 
#define lis_solver_get_preconname_f F77_FUNC_(lis_solver_get_preconname_f_, LIS_SOLVER_GET_PRECONNAME_F) 
#define lis_solver_set_optionC_f F77_FUNC_(lis_solver_set_optionc_f_, LIS_SOLVER_SET_OPTIONC_F) 
/**************/
/* ESOLVER     */
/**************/
#define lis_esolver_create_f F77_FUNC_(lis_esolver_create_f_, LIS_ESOLVER_CREATE_F) 
#define lis_esolver_destroy_f F77_FUNC_(lis_esolver_destroy_f_, LIS_ESOLVER_DESTROY_F) 
#define lis_esolve_f F77_FUNC_(lis_esolve_f_, LIS_ESOLVE_F) 
#define lis_esolver_set_option_f F77_FUNC_(lis_esolver_set_option_f_, LIS_ESOLVER_SET_OPTION_F) 
#define lis_esolver_get_iters_f F77_FUNC_(lis_esolver_get_iters_f_, LIS_ESOLVER_GET_ITERS_F) 
#define lis_esolver_get_itersex_f F77_FUNC_(lis_esolver_get_itersex_f_, LIS_ESOLVER_GET_ITERSEX_F) 
#define lis_esolver_get_time_f F77_FUNC_(lis_esolver_get_time_f_, LIS_ESOLVER_GET_TIME_F) 
#define lis_esolver_get_timeex_f F77_FUNC_(lis_esolver_get_timeex_f_, LIS_ESOLVER_GET_TIMEEX_F) 
#define lis_esolver_get_evalues_f F77_FUNC_(lis_esolver_get_evalues_f_, LIS_ESOLVER_GET_EVALUES_F)
#define lis_esolver_get_evectors_f F77_FUNC_(lis_esolver_get_evectors_f_, LIS_ESOLVER_GET_EVECTORS_F) 
#define lis_esolver_get_residualnorm_f F77_FUNC_(lis_esolver_get_residualnorm_f_, LIS_ESOLVER_GET_RESIDUALNORM_F) 
#define lis_esolver_get_rhistory_f F77_FUNC_(lis_esolver_get_rhistory_f_, LIS_ESOLVER_GET_RHISTORY_F) 
#define lis_esolver_get_esolver_f F77_FUNC_(lis_esolver_get_esolver_f_, LIS_ESOLVER_GET_ESOLVER_F) 
#define lis_esolver_get_esolvername_f F77_FUNC_(lis_esolver_get_esolvername_f_, LIS_ESOLVER_GET_ESOLVERNAME_F) 
#define lis_esolver_set_optionC_f F77_FUNC_(lis_esolver_set_optionc_f_, LIS_ESOLVER_SET_OPTIONC_F) 
/**************/
/* MATVEC     */
/**************/
#define lis_matvec_f F77_FUNC_(lis_matvec_f_, LIS_MATVEC_F) 
#define lis_matvect_f F77_FUNC_(lis_matvect_f_, LIS_MATVECT_F) 
/**************/
/* SYSTEM     */
/**************/
#define lis_set_comm_world_f F77_FUNC_(lis_set_comm_world_f_, LIS_SET_COMM_WORLD_F)
#define lis_finitialize_f F77_FUNC_(lis_finitialize_f_, LIS_FINITIALIZE_F) 
#define lis_finalize_f F77_FUNC_(lis_finalize_f_, LIS_FINALIZE_F) 
#define lis_wtime_f F77_FUNC_(lis_wtime_f , LIS_WTIME_F)
#define CHKERR_f F77_FUNC_(chkerr_f_, CHKERR_F) 
#define lis_set_argv_begin_f F77_FUNC_(lis_set_argv_begin_f_, LIS_SET_ARGV_BEGIN_F) 
#define lis_set_argv_f F77_FUNC_(lis_set_argv_f_, LIS_SET_ARGV_F) 
#define lis_set_argv_end_f F77_FUNC_(lis_set_argv_end_f_, LIS_SET_ARGV_END_F) 
#define lis_arg2args_f F77_FUNC_(lis_arg2args_f_, LIS_ARG2ARGS_F) 
#define lis_input_f F77_FUNC_(lis_input_f_, LIS_INPUT_F)
#define lis_input_matrix_f F77_FUNC_(lis_input_matrix_f_, LIS_INPUT_MATRIX_F)
#define lis_input_vector_f F77_FUNC_(lis_input_vector_f_, LIS_INPUT_VECTOR_F)
#define lis_output_f F77_FUNC_(lis_output_f_, LIS_OUTPUT_F) 
#define lis_output_matrix_f F77_FUNC_(lis_output_matrix_f_, LIS_OUTPUT_MATRIX_F) 
#define lis_output_vector_f F77_FUNC_(lis_output_vector_f_, LIS_OUTPUT_VECTOR_F) 
#define lis_solver_output_rhistory_f F77_FUNC_(lis_solver_output_rhistory_f_, LIS_SOLVER_OUTPUT_RHISTORY_F) 
#define lis_esolver_output_rhistory_f F77_FUNC_(lis_esolver_output_rhistory_f_, LIS_ESOLVER_OUTPUT_RHISTORY_F) 

追記

これだけじゃ不十分ぽい。結果がおかしいようなので、簡単な例で検証する必要がありそう。