LoginSignup
5
4

More than 5 years have passed since last update.

NVCの御紹介と称する事実上のcygwin port修正作業

Posted at

要約

自由なVHDLシミュレータを使いましょう.
手堅くGHDLでも良いですが,個人的にはNVCが絶賛開発中でオモロいです.
NVCは,Nick Gassonさん(以下nickgたん)が開発しているVHDLシミュレータで,

  • VHDL-1993以上を目標.
  • ライセンスはGPLv3を採用. ← 重要
  • Cで書かれている.
  • バックエンドにLLVMを採用.
  • 波形出力にFSTを採用.
  • Tclインタラクティブモードをサポート.
  • statement/branch/conditionのカバレッジをサポート.

と言う特徴があります.
x86かx86_64なLinuxにgit cloneしてテキトーにhogeれば多分それなりに動きます.

以下,cygwinへのportで行った修正作業を書き散らしておきます.
FLOSS開発に興味の無い方は以下の駄文は無視して下さい.
貴重な時間を使って読むべき意味のあるVHDLネタはここで終わりです.

ヤクの毛の生え具合:ぶっ壊れたconfigure

Yak_Yama.jpg

太古の昔にcygwinにportしたのですが,あれからnickgたんがコンスタント且つアクティブにコミットをキメ続けている御蔭でcygwinではconfigureも通らない程にぶっ壊れて仕舞いました.

nvc-configure-on-cygwin-1st
$ ./configure --enable-native --enable-coverage
[SNIP]
checking for BZ2_bzclose in -lbz2... yes
llvm-config: error: components given, but unused
[SNIP]
checking for LLVM (engine bitreader bitwriter)... yes
checking for LLVM shared library... yes
[SNIP]
checking for CHECK... yes
which: invalid option -- s
which: invalid option -- t
which: invalid option -- d
which: invalid option -- =
which: invalid option -- g
which: invalid option -- n
which: invalid option -- u
which: invalid option -- 9
which: invalid option -- 9
./configure: line 7487: AX_CHECK_GNU_MAKE: command not found
checking that generated files are newer than configure... done
[SNIP]

307px-Challenge_accepted.png

ヤクの毛刈り:llvm-configを直す

llvm-configでコケているっぽいので,ソースを追います.

nvc/configure.ac
AX_LLVM_C([engine bitreader bitwriter])
configure
LLVM_CFLAGS=`$ac_llvm_config_path --cflags`
LLVM_CXXFLAGS=`$ac_llvm_config_path --cxxflags`
LLVM_LDFLAGS="$($ac_llvm_config_path --ldflags)"
LLVM_LIBS="$($ac_llvm_config_path --libs engine bitreader bitwriter)"
LLVM_VERSION="$($ac_llvm_config_path --version)"
LLVM_CONFIG_BINDIR="$($ac_llvm_config_path --bindir)"
LLVM_LIBDIR="$($ac_llvm_config_path --libdir)"

幾つか試すと,llvm-config --libs engine bitreader bitwriterでコケている事が分かります.

llvm-config-is-broken
$ llvm-config --libs engine bitreader bitwrtiter
-lLLVM-3.1
llvm-config: error: components given, but unused
[SNIP]

penguin-llvm-314.jpg

ググると,LLVM本家のBug 13430が釣れました.
報告日は2012/07/21と一年以上絶賛放置中なので,自分で直すしかありません(白目

ゴニョった結果,cygwin ports由来のパッチが犯人である事が分かりました.cygwin ports側の問題なので,llvm.cygport直しました

報告はしたので,公式の方はそのうちテキトーに処理されると思います.
取り敢えず,ローカルの方はllvm.cygportを弄っている間に出来たパッケージをsetup-{x86,x86_64}.exeのInstall from Local Directoryでぶっ込んでおきます.

deploy-local-hotfix-llvm
$ cygport llvm.cygport all
[SNIP]

$ mkdir -p /distfiles/hotfix/cygwin/release ; \
  cp -a llvm-3.1-4/dist/llvm /distfiles/hotfix/cygwin/release/ ; \
  find /distfiles/hotfix/cygwin/release -type d | \
    xargs genini | bzip2 -c > /distfiles/hotfix/cygwin/setup.bz2

[then Install from Local Directory by using setup-{x86,x86_64}.exe.]

おもむろに,再びconfigureを実行

nvc-configure-on-cygwin-2nd
$ ./configure --enable-native --enable-coverage
[SNIP]
checking for BZ2_bzclose in -lbz2... yes
checking for LLVM (engine bitreader bitwriter)... yes
checking for LLVM shared library... yes
[SNIP]
checking for CHECK... yes
which: invalid option -- s
which: invalid option -- t
which: invalid option -- d
which: invalid option -- =
which: invalid option -- g
which: invalid option -- n
which: invalid option -- u
which: invalid option -- 9
which: invalid option -- 9
./configure: line 7487: AX_CHECK_GNU_MAKE: command not found
checking that generated files are newer than configure... done
[SNIP]

直りました.

ヤクの毛刈り:which: invalid optionを直す

which: invalid optionがキモいので,ソースを追います.

nvc/configure.ac
# On cygwin local headers can sometimes be included instead
# of system ones which is worked around using -I-. A better
# solution would be to have automake use -iquote.
case $host_os in
  *cygwin* ) CFLAGS="$CFLAGS -I-" ;;
esac

AC_DEFINE_UNQUOTED([SYSTEM_CC], ["$(which $CC)"], [System compiler])

CC-std=gnu99が紛れ込んでいる様なので,どうにかします.
ついでに大昔に追加したヘッダファイルをアレするクソな修正は,既にnvc/src/rt/signal.h御亡くなりになっているの様なのでポイすると,こうなります

${parameter%%word}で最長サフィックスを削除する黒魔術はdash互換です! ← 重要

おもむろに(以下略

nvc-configure-on-cygwin-3rd
$ ./autogen.sh && ./configure --enable-native --enable-coverage
[SNIP]
checking for CHECK... yes
./configure: line 7481: AX_CHECK_GNU_MAKE: command not found

直りました.

ヤクの毛刈り:AX_CHECK_GNU_MAKE: command not foundを直す

ググると,GNU本家のAutoconf Archiveのページが釣れました.

Autoconf Archiveをgit clone${AA}にぶっこ抜いておいて,ax_check_gnu_make.m4の追加とその他m4なファイルを更新したらおもむろに(以下略

nvc-configure-on-cygwin-4th
$ touch m4/ax_check_gnu_make.m4 && \
   for f in m4/*.m4 ; do [-f ${AA}/${f}] && cp ${AA}/${f} ${f} ; done && \
   ./autogen.sh && ./configure --enable-native --enable-coverage
[SNIP]
checking for CHECK... yes
checking for GNU make... make
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating src/rt/Makefile
config.status: creating test/Makefile
config.status: creating lib/Makefile
config.status: creating lib/std/Makefile
config.status: creating lib/ieee/Makefile
config.status: creating lib/synopsys/Makefile
config.status: creating lxt/Makefile
config.status: creating fst/Makefile
config.status: creating config.h
config.status: config.h is unchanged
config.status: executing depfiles commands

直りました.

ヤクの毛の生え具合:ぶっ壊れたmake

640px-Yaks_auf_der_Enzianwiese.JPG

まぁ,configureがぶっ壊れていたので,makeが通るワケないですね(白目

nvc-make-on-cygwin-1st
$ make
[SNIP]
  CC       util.o
util.c:546:13: error: ‘is_debugger_running’ defined but not used [-Werror=unused-function]
 static bool is_debugger_running(void)
             ^
[SNIP]

307px-Challenge_accepted.png

ヤクの毛刈り:NO_STACK_STACEを直す

src/util.cを見てみると,スタックトレースを取る為に黒魔術をしているトコロをcygwinにportするのダルくて,大昔にNO_STACK_TRACEでズルしていたトコロが古くなっていた様なので,直します

penguin-no-trace.jpg

ヤクの毛刈り:ctype.h関連を直す

nvc-make-on-cygwin-2nd
$ make
[SNIP]
  CC       elab.o
elab.c: In function ‘elab_push_scope’:
elab.c:832:10: error: array subscript has type ‘char’ [-Werror=char-subscripts]
          *p = tolower(*name);
          ^
elab.c:853:13: error: array subscript has type ‘char’ [-Werror=char-subscripts]
             *p = tolower(*id);
             ^
[SNIP]

ctype.hの文字操作は,マクロで実装されている事があります.
cygwinが使っているnewlibを-std=gnu99で使うと,少なくとも一部はマクロになる様です.
取り敢えず,intにキャストするのが無難でしょう.
該当箇所は,

find-ctype-funcitions
$ for f in $(grep -e '_EXFUN' /usr/include/ctype.h | \
         sed -e 's/.*\([it][so].*\),.*/\1/' | sort -u) ; \
   do \
      grep -n -e $f $(find . -name '*.c' -or -name '*.h' -or -name '*.y' -or -name '*.l') ; \
   done
./src/sem.c:3148:      const bool operator = !isalpha((uint8_t)*istr(name));
./src/sem.c:3166:      const bool operator = !isalpha((uint8_t)fname[0]);
./src/common.c:236:         while (isdigit(*str) || (*str == '_')) {
./src/parse.c:6283:      int n = (isdigit((int)*p) ? (*p - '0')
./src/parse.y:2632:      int n = (isdigit((int)*p) ? (*p - '0')
./src/common.c:229:   while (isspace(*str))
./src/common.c:252:         for (p = copy; (*p != '\0') && !isspace(*p); p++, str++) {
./src/common.c:281:      if (!isspace(*str++))
./src/util.c:211:      if ((*p == '\n') || (isspace((uint8_t)*p) && col >= right)) {
./src/parse.c:6284:               : 10 + (isupper((int)*p) ? (*p - 'A') : (*p - 'a')));
./src/parse.y:2633:               : 10 + (isupper((int)*p) ? (*p - 'A') : (*p - 'a')));
./src/common.c:220:         *p++ = tolower(*str++);
./src/elab.c:79:      *p = tolower((uint8_t)*p);
./src/elab.c:832:         *p = tolower(*name);
./src/elab.c:853:            *p = tolower(*id);
./src/lib.c:188:      *p = tolower((uint8_t)*p);
./src/parse.c:4125:        *p = tolower((int)*p);
./src/parse.y:1194:        *p = tolower((uint8_t)*p);
./fst/fstapi.c:5926:                    case 'x':       val[0] = toupper(src[++i]);
./fst/fstapi.c:5927:                                    val[1] = toupper(src[++i]);
./src/common.c:72:      *p = toupper((uint8_t)*p);
./src/common.c:256:               *p = toupper(*p);
./src/lexer.c:2800:      *p++ = toupper((int)*str);
./src/lexer.l:352:      *p++ = toupper((uint8_t)*str);
./src/lib.c:88:      *p = toupper((uint8_t)*p);
./src/nvc.c:61:      *p = toupper((uint8_t)*p);

なので,単項演算子の二重評価回避も考慮して直した後,おもむろに(以下略

nvc-make-on-cygwin-3rd-for-src
$ make
[SNIP]
  CC       nvc.o
  CXXLD    nvc.exe
Making all in lib
[SNIP]

src/nvc.exeのビルドまで通りました.

ヤクの毛の生え具合:ぶっ壊れたlib

640px-White_yack_col.jpg

でも,lib以下でライブラリがbootstrap出来ません(白目

nvc-make-on-cygwin-3rd-after-src
$ make
[SNIP]
Making all in lib
Making all in std
  NVC      std/STD.STANDARD
  NVC      std/STD.TEXTIO
  NATIVE   std/STD.TEXTIO
/tmp/ccy66pvE.o:fake:(.text+0x2b): undefined reference to `_file_open'
/tmp/ccy66pvE.o:fake:(.text+0x57): undefined reference to `_file_open'
/usr/lib/gcc/i686-pc-cygwin/4.8.2/../../../../i686-pc-cygwin/bin/ld: /tmp/ccy66pvE.o: bad reloc address 0x20 in section `.eh_frame'
collect2: error: ld returned 1 exit status
** Fatal: /usr/bin/gcc failed with status 1
Makefile:498: recipe for target 'std/STD.TEXTIO' failed
[SNIP]

307px-Challenge_accepted.png

ヤクの毛刈り:共有ライブラリの拡張子

色々モニョると,少なくとも--enable-nativeでない場合の面倒を余り見ていない雰囲気が伝わってきます.
取り敢えず,共有ライブラリの拡張子が決め打ちになっている箇所を変更してみました

しかし,結果が変わりません...

以下にある様に後で悟った事ですが,当該拡張子向けの変更は意味が無かった様です.
適切なパスでdlopen()する事が前提であれば,少なくともcygwinでは.soでも.dllでも動きます.

ヤクの毛刈り:DLL黒魔術

更に調べると,

lib/std/std/_STD.TEXTIO.s
    calll   __file_open
src/rt/rtkern.c
void _file_open(int8_t *status, void **_fp, uint8_t *name_bytes,
                int32_t name_len, int8_t mode)
{
src/rt/rtkern.c
static void rt_one_time_init(void)
{
[SNIP]
   jit_bind_fn("_file_open", _file_open);
objdump-t-src-nvc.exe
$ objdump.exe -t src/nvc.exe | grep -e '_file_open'
[3998](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00078840 __file_open
[3999](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00025b20 ___gcov0._file_open
[4088](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00006d88 ___gcov_._file_open

となっている事が分かります.
つまり,DLLがビミョい臭い.
ググると,stackoverflowのページとsourceware.orgのautobookのページが釣れました.

他の環境にも影響が出そうなので,pull requestを出しつつ,nickgたんに御伺いを奉っておきます.

ヤクの毛の生え具合:GTKWave

640px-Schwarzer_Yakbulle.JPG

NVCがちゃんとport出来た暁には,FSTを読める波形ビューワーが欲しいので,GTKWaveが欲しいですね.
もちろん,cygwinでは公式パッケージになっていません(白目
pull resuestが処理されるまでのヒマつぶしにportします.

307px-Challenge_accepted.png

ヤクの毛刈り:Judyをパッケージ化

GTKWaveのsvn trunkをぶっこ抜いてきて,configure --helpすると,

gtkwave-configure-help
$ ./configure --help
[SNIP]
 --enable-judy           Enables Judy array support
[SNIP]

とあり,Judyを使うっぽいので,ちょちょいとパッケージにしてsetup-{x86,x86_64}.exeのInstall from Local Directoryでぶっ込んでおきます.

deploy-local-proposed-judy
$ cygport judy.cygport all
[SNIP]

$ mkdir -p /distfiles/proposed/cygwin/release ; \
  cp -a judy-1.0.5-1/dist/judy /distfiles/proposed/cygwin/release/ ; \
  find /distfiles/proposed/cygwin/release -type d | \
    xargs genini | bzip2 -c > /distfiles/proposed/cygwin/setup.bz2

[then Install from Local Directory by using setup-{x86,x86_64}.exe.]

ヤクの毛刈り:GTKWaveをパッケージ化

configure --helpを参照しつつ,ちょちょいとパッケージにしてsetup-{x86,x86_64}.exeのInstall from Local Directoryでぶっ込んでおきます.

deploy-local-proposed-gtkwave
$ cygport gtkwave.cygport all
[SNIP]

$ cp -a gtkwave-3.3.52-1/dist/gtkwave /distfiles/proposed/cygwin/release/ ; \
  find /distfiles/proposed/cygwin/release -type d | \
    xargs genini | bzip2 -c > /distfiles/proposed/cygwin/setup.bz2

[then Install from Local Directory by using setup-{x86,x86_64}.exe.]

試しに付属のexampleを表示させてみます.

gtkwave-on-cygwin-x.jpg

パッと見,動いているっぽいですね.

penguin-xp.jpg

ヤクの毛の生え具合:ぶっ壊れたlib,再び

640px-White_yack_col.jpg

GTKWaveをパッケージ化している間に,nickgたんが光速でマージしてくれました.

ヤクの毛刈り:checkを更新

取り敢えず,--enable-nativeは保留して,make checkまで通す事にします.
cygwinのcheckぶっ壊れていたので,ちょちょいと更新して,setup-{x86,x86_64}.exeのInstall from Local Directoryでぶっ込んでおきます.

deploy-local-proposed-check
$ cygport check.cygport all
[SNIP]

$ cp -a check-0.9.11-1/dist/check /distfiles/hotfix/cygwin/release/ ; \
  find /distfiles/hotfix/cygwin/release -type d | \
    xargs genini | bzip2 -c > /distfiles/hotfix/cygwin/setup.bz2

[then Install from Local Directory by using setup-{x86,x86_64}.exe.]

checkのバージョンが変わったので,一応,configureから(以下略

nvc-make-on-cygwin-4th
$ ./configure --disable-native --enable-coverage && \
    make -C test clean && make check
[SNIP]
===================
All 12 tests passed
===================

--disable-nativeですが,make checkまで通りました.

ヤクの毛刈り:DLL黒魔術,再び

やっぱり,--enable-nativeしたいので,モニョモニョした結果,幾つか悟りが啓けました

cygwinのDLLは,作成時に未定義参照を許さない様です.
NVCではsrc/rt/jit.cでDLLをdlopen()しますが,当該DLLの中にはsrc/rt/rtkern.c内の関数や別のDLL内の関数を参照する様なネイティブコードを生成する事があります.
この様な場合,インポートライブラリと呼ばれるモノを別途作成して,コイツとリンクしてDLLを作成すれば良い様です.
一般的なやり方は,cygwin本家のページにありましたが,この方法はボツにしました.
理由は幾つかあります.

  • 例えば,_file_open()は,src/nvc.exeの中に実体がある.
    src/rt/rekern.csrc/rt/rekern.osrc/rt/libnvc-rt.asrc/nvc.exe
  • cygwinの為だけに,こんなクソなコマンドを仕込みたくない.
    NVCが生成するネイティブコードはVHDLのコードとしての依存関係も継承する為,src/link.cを大幅に変更しなければならなくなる.
  • nickgたんはlibtoolがキライらしい.
    NVC自身が元々libtoolを使っていない.

つまり, 或るDLLをdlopen()する実行形式オブジェクト内にあるシンボルを当該DLLから参照する際,当該DLLのリンク時に未定義参照を解決する為のインポートライブラリを,クソなコマンドやlibtoolを使わずに作成したい.

(「そんな都合の良い方法あるんかいな...」と思いながら)探しました...
スタッフみんな(オレ一人),一生懸命探しました...
そしたらね...見つかりました!
PostgreSQLの野良パッチとしてお住まいでした...(島田紳助

結局,当該実行形式オブジェクトのリンク時に-Wl,--export-all-symbols -Wl,--out-implib=...を付加してインポートライブラリを同時に作成する方法を採用する事にしました.

pull requestすると,nickgたんが再び光速でマージしてくれました.
しかも,わざわざドコからかWindowsマシンを借りてきたらしく,nickgたん自らcygwin portを直し始めると言う不測の事態が発生し,更にゴニョゴニョした結果,--enable-native動く様になりました!!1

ヤクの毛の生え具合:今後の課題

FIXME: 画像ファイルのアップロード制限の為,新しいヤクの写真が貼れない.
FIXME: と言うか,下書き保存やプレビューの反応が悪くて, アップロードしたリンクが保存されずに消えた...

ヤクの毛刈り(予定):カバレッジ

調子に乗って,カバレッジを毒味した所,死亡しました.

nvc-make-on-cygwin-5th
$ make cov-reset
make[1]: lcov: Command not found
Makefile:781: recipe for target 'cov-reset' failed
[SNIP]

lcovは公式パッケージに無いですね.
しかも,dev-perl/GD依存 = CPAN沼が不可避.
カバレッジはかざり ですが,気が向いたらゴニョるかもしれません.

ヤクの毛刈り(予定):パッケージ化

リリースはかざり ですが,パッケージ化はしたい.

ヤクの毛刈り(予定):スタックトレース対応

コレコレを参考に気が向いたらゴニョる.

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4