Visual Studio 2013 で msvcrt.dll にリンクする

Visual Studio Community 2013 の cl.exe によるビルドにおいて、生成される実行ファイルが msvcr120.dll ではなく msvcrt.dll をリンクするようにする方法・更にはどちらにもリンクさせない方法をメモしておく。

Visual Studio Community 2013 ダウンロードサイト

Microsoft が個人開発者や小規模組織等向けに公開している Visual Studio 無償版の名称は、Visual Studio Community である。

f:id:ray0mg:20150827213445p:plain

Visual Studio Community 2013 with Update 5 (ISO)
go.microsoft.com/fwlink/?LinkId=532496
Visual Studio 2013 Language Pack (日本語)
go.microsoft.com/fwlink/?LinkID=320680

情報源を元にやってみる

タイトルの方法については以下のサイトに全て書かれている。

すなわち、Windows Driver Kit の中に、良い msvcrt.lib がある。

Download Windows Driver Kit Version 7.1.0 from Official Microsoft Download Center
download.microsoft.com/download/4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO

なんとかして msvcrt.lib を取り出す

F(ISO):\WDK から以下のファイルを例えば C:\wdk\ に置く。

  • libs_x86fre.msi
  • libs_x86fre_cab001.cab

C:\wdk\ にてコマンドプロンプトで以下を実行する。

msiexec /a libs_x86fre.msi /qb targetdir=C:\wdk\temp\

これで CAB 圧縮ファイルがうまい具合に展開されて、目当ての msvcrt.lib が以下のパスに出現している。

  • C:\wdk\temp\WinDDK\7600.16385.win7_wdk.100208-1538\lib\Crt\i386\msvcrt.lib

この msvcrt.lib を C:\wdk\lib\ にでも入れておく。

使用例

以下のコードは、cl.exe でうまくビルドできるよう環境変数を整えるためのバッチファイルである。

@echo off
setlocal
set path=%path%;"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin"
set include="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src";"C:\Program Files (x86)\Windows Kits\8.1\Include\shared";"C:\Program Files (x86)\Windows Kits\8.1\Include\um";
set lib="C:\wdk\lib";"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib";"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86"
if "%*" GTR "" (cmd /c %*) else (cmd /k prompt[VS]$P$G)
endlocal

このように、環境変数 lib に C:\wdk\libなるべく先頭に入れておく。

これで、ビルドする際には良い msvcrt.lib が使用され、msvcrt.dll にリンクされるようになる。

あるいは、C言語ソースコード中に標準ライブラリの関数等を使っておらず、リンカオプションで独自にエントリポイントを指定 /ENTRY:__start__ した場合は、msvcrt.dll へのリンクもされなくなる。

【GCC】implicit declaration of function '_wtoi' 解決方法

  • 問題 : GCC で C コンパイル時の警告文「warning: implicit declaration of function '_wtoi' [-Wimplicit-function-declaration] int n = _wtoi(argv[1]);」を解消したい
  • 答え : #undef __STRICT_ANSI__

コンパイルする

以下の C言語 ソースコードsrc.c とする。

#include <windows.h>
int main() {
  // コマンドライン引数(1番目)を数値変換して出力
  int length;
  LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &length);
  int n = _wtoi(argv[1]);
  TCHAR s[99];
  wsprintf(s, TEXT("%d"), n);
  MessageBox(NULL, s, TEXT(""), MB_OK);
  return 0;
}

警告が出る

コンパイル gcc src.c -std=c11 すると、以下の警告文が表示される。

src.c: In function 'main':
src.c:6:3: warning: implicit declaration of function '_wtoi' [-Wimplicit-funct
ion-declaration]
   int n = _wtoi(argv[1]);

この意味は、「暗黙に宣言された関数 _wtoi を使っています」だ。

インクルードし忘れか?

きっと _wtoi が宣言されたヘッダファイルをインクルードしていないから、こんな警告をされるのだ。ならば、インクルードしよう。C:\MinGw\include\ 内を検索する。

結果はこれだ。

  • stdlib.h
  • tchar.h

なので、#include <stdlib.h>#include <tchar.h>src.c に追加して再コンパイルするも、同じ警告をされてしまった。(それどころか別のエラーまで発生する始末)

よくよく調べてみると、windows.h にて、遠回しにこれらのヘッダファイルがインクルードされるようになっていたので、全く意味がなかった。

原因は stdlib.h のソースだった

明示的に宣言しているはずなのに、どうして暗黙の宣言だと警告されてしまうのか。その原因は、stdlib.h 内にある _wtoi の宣言方法にあった。以下に、当該箇所を示す。

#if !defined (__STRICT_ANSI__)
_CRTIMP double __cdecl __MINGW_NOTHROW _wtof (const wchar_t *);
_CRTIMP int __cdecl __MINGW_NOTHROW    _wtoi (const wchar_t *);
_CRTIMP long __cdecl __MINGW_NOTHROW _wtol (const wchar_t *);
#endif

#if !defined (__STRICT_ANSI__) というブロックに囲われて宣言されている。「もし __STRICT_ANSI__ が定義されていないならば、_wtoi という関数を宣言しますよ」という意味だ。ゆえに、_wtoi が宣言されたヘッダファイルを正しくインクルードしていても、__STRICT_ANSI__ が定義されていれば、暗黙の宣言になってしまい、警告が出る。

そもそも「暗黙の宣言」とは何か。よくわからないが、#include <stdio.h> しなくとも printf が使えるのと同じで、自動的に宣言してくれる機能があるらしい。

GCC コマンドオプションによって結果が変わる

つまり、警告を出さないためには __STRICT_ANSI__ を定義しないようにすればいいことがわかる。どうすれば定義されないようにできるかというと、コンパイル時のオプションで -std=c11-std=c99 を指定せず、例えば -std=gnu1x を指定しておけば定義されなくなる。その証明は、以下のソースコードコンパイルで行うことができる。

以下の C言語 ソースコードnazo.c とする。

#include <windows.h>
int main() {
  TCHAR s[99];
  wsprintf(s, TEXT("%d"), __STRICT_ANSI__);
  MessageBox(NULL, s, TEXT(""), MB_OK);
  return 0;
}

コンパイル gcc nazo.c -std=c11 して、実行すると、メッセージボックスが現れ、「1」と表示される。

一方で、gcc nazo.c -std=gnu1x すると、以下のエラーが出てコンパイル失敗する。

nazo.c: In function 'main':
nazo.c:4:27: error: '__STRICT_ANSI__' undeclared (first use in this function)
   wsprintf(s, TEXT("%d"), __STRICT_ANSI__);
                           ^
nazo.c:4:27: note: each undeclared identifier is reported only once for each function it appears in

このことにより、__STRICT_ANSI__ の定義は、-std=c11 なら「有」となり、-std=gnu1x だと「無」になることがわかる。

強引だが解決できなくはない

ならば、-std=c11 時に行われる __STRICT_ANSI__ の定義を取り消せば、_wtoi が明示的に宣言されるようになるのであり、その方法として、「ソースコードの最初のほうに #undef __STRICT_ANSI__ を書いておく」というものがある。

#undef __STRICT_ANSI__
#include <windows.h>
int main() {
  // コマンドライン引数(1番目)を数値変換して出力
  int length;
  LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &length);
  int n = _wtoi(argv[1]);
  TCHAR s[99];
  wsprintf(s, TEXT("%d"), n);
  MessageBox(NULL, s, TEXT(""), MB_OK);
  return 0;
}

これで警告は出なくなる。

たかが警告だ放っておこう

しかしながら、ヘッダファイルが -std=c11 といった規格指示によって、何らかの意図があって _wtoi の宣言の有無を自動決定していくれているものを「警告をなくしたいから」という理由だけで影響範囲も考えず __STRICT_ANSI__ の定義を取り消すことはまずいことのきっかけになりそうなにおいを孕んでいる。

たかが警告だ。放っておこう。

Windows 無線 LAN 切断バグへの対処例

最近、PC (Windows 10) で無線 LAN インターネットをしていると、切断されてしまうことが多い。色々と試行錯誤をしているが、原因がはっきりしない。

試したこと~その1~

  • デバイスドライバを再インストールしたり、
  • 「ネットワークと共有センター」→「Wi-Fiのプロパティ」→「インターネット プロトコル バージョン 4 (TCP/IPv4)のプロパティ」→「TCP/IP 詳細設定」で、
    • 「LMHOST の参照を有効にする」をオフ
    • NetBIOS over TCP/IP を無効にする

したりと、色々いじっている。

f:id:ray0mg:20150824160932p:plain

不具合内容

「無線 LAN が切断される」の意味は、「無線ルーターが発信している SSID が見えなくなる」ということで、すなわち「無線ルーターバグる」のである。(PC でこの現象が起きてから、PSVita で無線 LAN 接続しようとしても、当該 SSID が一覧に表示されないので、PC 側だけの問題ではないのだ)

無線ルーターが物理的にぶち壊れてきたのではないかとも思ったが、まだ寿命ではないと信じたい。

試したこと~その2~

他の試行錯誤として、wlan プロファイルの種類を「パブリック ネットワーク」にすることもやった。これをやったあたりから、一日間、しばらくバグってないので、おそらく、これが効いているような気がする。

f:id:ray0mg:20150824160938p:plain

そもそも、Windows 8(.1) 時代はずっと「パブリック ネットワーク」にしていたのだが、Windows 10 にしてから、色んな設定の見直しの最中に、気まぐれで「プライベート ネットワーク」に変更した。これが良くなかったのではないか。

種類の変更は、以下のようにして行う。

  1. まずプロファイルを削除する。コマンド プロンプトで netsh wlan delete profile 当該SSID名 でできるはず。(できない場合は、netsh wlan show profiles で調べる)
  2. プロファイルを新規作成。接続するときの質問「このネットワーク上の他の PC やデバイスが、この PC を検出できるようにしますか?」で「いいえ」を選択
  3. 完了

f:id:ray0mg:20150824160934p:plain

結論

原因はよくわからない。どんな方法が有効なのかもはっきりしない。