トップ回答者
環境変数を定義したバッチファイルから起動したVisualBasicのデバッグ実行時、定義した環境変数を見ていない?

質問
-
VS2008です。あるソリューション中に次の二つのプロジェクトがあります。
library.dll (C++/CLI)
testapp.exe (VB.NET)
testapp.exe は library.dll を参照しており、library.dll はソリューション外にあるサードパーティ製 DLL 3rdparty.dll にダイナミックリンクしています。
このソリューションファイルを開く際以下のようなバッチファイルを書いて、それを実行しています。
set MYLIB="E:\path\to\lib"
set PATH="%MYLIB%\..\bin;%PATH%"
start "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe" このソリューションファイル.sln
library.dll がリンクしている 3rdpary.dll のヘッダなどは MYLIB として定義されており、3rdparty.dll 本体は E:\path\to\bin に設置されています。
library.dll は正常にビルドすることができ、testapp.exe もビルドまでは正常にいくのですが、デバッグ実行を行うと、どうも環境変数 PATH を見ていないらしく、FileNotFound 例外が出てしまいます。
testapp.exe のバイナリと同じ位置( このソリューション/testapp/bin/Debug 配下 )に library.dll が吐かれているので、3rdparty.dll の方が見えていないようです。
3rdparty.dll を testapp.exe および library.dll が吐かれたディレクトリに配置してやれば、正常に実行できます。
そこで、testapp.exe のプロパティ>デバッグ>作業ディレクトリを 3rdparty.dll がある E:\path\to\bin に設定してやると、正常に実行できましたが、複数の環境で開発をしているソリューションなので
プロジェクトファイルに個人の作業マシンのパスを入力することができません。
作業ディレクトリを $(MYLIB)\..\bin と設定しても、「入力したディレクトリは存在しません」と環境変数を解釈してくれていないようです。
1) 開発者の作業マシンの環境変数はいじれないので、バッチファイルから環境変数付きで devenv.exe を起動している。
2) 例に上げた 3rdparty.dll は、実際には一つのファイルではなく、さらに数百 MB もあるので、(例で言う)E:\path\to\bin から testapp/bin/Debug にそれらをコピーしてくる、という事はしたくない。
3) 例で言う E:\path\to\bin および MYLIB として定義されている E:\path\to\lib は、作業マシンによって違う場所を差している。統一することも出来ない。
という条件の許、何かスマートな解決方法はないでしょうか。
回答
-
DEVPATH環境変数を使われてはどうでしょう。PATH環境変数はアセンブリの検索に使えなかったと思います。
http://msdn.microsoft.com/ja-jp/library/cskzh7h6%28v=vs.100%29.aspx
この方法はアセンブリ構成ファイルを変更する必要がありますが開発環境であればDLLの位置にかかわらずどのマシンでも同じ設定になります。
リリースの時には消す必要があります。
subversionのブランチが使えるのであれば、開発用、リリース用を用意しておくと良いと思います。
http://systemartlaboratory.com/
すべての返信
-
リプライありがとうございます。
> 基本的には環境を統一する1択だと思います。
オープンソースプロジェクトなど、不特定多数の開発者が任意の開発環境で開発を行うプロジェクトをご存じならご理解頂けると思いますが、開発環境をすべて統一することができないプロジェクトも実際には存在します。特に大規模なシステムを開発することになると、プロジェクトをモジュール単位で個々の開発者(社内とは限りません。例えば外注など)に割り振って開発することも珍しくありません。 aviator___ さんがおっしゃっている「基本的」は、何を基本とされているか存じませんが、条件に「統一はできない」と名言している以上、それに従った回答を頂けると幸いです。
> なぜ参照パスを絶対パス前提で会話されているのか
絶対パスを前提として会話しているつもりはありません。事実、例として提示しているバッチファイルでは、パス中に相対パス「..」を盛り込んでいますが・・・。
> vbprojファイルのHintPathって所をご確認下さい。
ありがとうございます。確認いたします。
> 参照パスはアプリの内部情報
「Makefile のような柔軟な開発ができるものではない、VisualStudio でブラックボックス化されている部分は、手を加えずに諦めた方が良い」ということでしょうか。確かに、私も VisualStudio、特に VB.NET の開発環境周りにそこまでの柔軟かつ高度な開発ができるとは考えていません。
総じてこちらの質問の仕方が悪かったようです。申し訳ございません。
バッチファイルから起動した開発環境 Visual Studio は、そのバッチファイル中で定義した環境変数を利用できるというのが私の認識です。(事実、バッチファイル中で定義したライブラリパスを VisualStudio のビルド時に使用することができました)
しかし、いざ VB.NET プロジェクトで「デバッグ実行」を実行した際、testapp.exe はバッチファイル中で定義した環境変数 PATH を読んでいない模様です。
どうしたら VB.NET でデバッグ実行したプロセスから環境変数を利用できるようになるのでしょうか。
という質問にするべきでした。
-
とりあえず、*.vbproj、*.csprojなどの.projファイルはdevenvではなくMSBuildが処理しています。Visual Studio 2010からは.vcxprojによりC++に関してもMSBuildが処理するようになりました。リンク先にもありますが、書式や処理内容は公開されていて自由に編集できます。
コピーしたくなくて環境がバラバラと言われるとどうしたものやら…? 開発中とは別にリリース?時にはどうするのでしょうか? 開発中もリリースに合わせて処理すればいいような。例えばリリース形態によってはLoadLibraryで読み込めるよう設定してしまうとか。
-
佐祐理様
何度もリプライを頂き、申し訳ありません。
>devenvではなくMSBuildが処理しています
なるほど、MSBuild が一環して環境を提供しているのですね。
VS2008 環境ですが、これから勉強してみます。
> コピーしたくなくてもう少し具体的にコピーしたくない理由を申しますと、
1) 開発者が作業環境として利用している Windows の「一部」は仮想環境で、システムを終了したらまっさらな状態に戻る。ネイティブ環境の開発者もある。
2) 基本的にまっさらな状態から、Subversion で作業コピーをチェックアウトしてきて、作業を行う。例外もある。
3) コミット後、またまっさらな状態に戻す。ただし、3rdparty.dll はネットワークドライブ上にあるので、作業環境からダイナミックにアクセス可能。
4) パスを通すか実行時リンク LoadLibrary さえすれば、動的リンクが可能なのが DLL なので、わざわざ作業の度にローカルの出力フォルダに持ってくるのは本末転倒のような・・・。という考えがありました。
リリース版は、VisualStudio の機能を利用しない独自のスクリプトで配布形式を作成しますので、特に問題にはなっておりません。
また、名前のとおり 3rdparty.dll は別の組織で開発されているものです。
> 環境がバラバラ
昔の Windows アプリケーションのように「Cドライブの直下に決め打ちでインストールさせる!」みたいな力技ができなくなっている昨今ですので、ファイル構造の差異くらいだったら環境変数に定義させておいて、開発者ごとに切り替えて使うのがスマートなんじゃないかなあ、と思いました。
UNIX 風に言うと、
PATH=/path/to/bin cgdb testapp
のようにデバッグ実行時に環境変数を指定できればな、と思っただけなんですが、私の質問も的を得ていませんでした。申し訳ありません。
-
ピンポイントだけで申し訳ないのですが、勘違いされているようなので指摘しておきます。
そこで、testapp.exe のプロパティ>デバッグ>作業ディレクトリを 3rdparty.dll がある E:\path\to\bin に設定してやると、正常に実行できましたが、複数の環境で開発をしているソリューションなので
プロジェクトファイルに個人の作業マシンのパスを入力することができません。この設定値は、vbproj ではなく、vbproj.user といったプロジェクトファイルとは別のユーザー設定ファイルに保存されます。
通常、*.user ファイルはレポジトリにチェックインせずに管理するはずなので、個人の作業マシンのパスを入れても支障がないはずなのですが、どうなっていますか?// これでうまくいっても、ばっさり消える環境では毎回設定が必要ですが…。
- 編集済み AzuleanMVP, Moderator 2012年6月4日 13:53
-
DEVPATH環境変数を使われてはどうでしょう。PATH環境変数はアセンブリの検索に使えなかったと思います。
http://msdn.microsoft.com/ja-jp/library/cskzh7h6%28v=vs.100%29.aspx
この方法はアセンブリ構成ファイルを変更する必要がありますが開発環境であればDLLの位置にかかわらずどのマシンでも同じ設定になります。
リリースの時には消す必要があります。
subversionのブランチが使えるのであれば、開発用、リリース用を用意しておくと良いと思います。
http://systemartlaboratory.com/
-
リプライありがとうございます。
3rdparty.dll の配置を含めた構成が、完成していれば良いのですが、こちらも外部で開発途中である為、暫定的な構成でのみ提供されているのが現状です。
もちろん、最終的な配布形態と同じ状態でデバッグするのがベターだとは理解しています。ただ、本題から少し離れた内容になるので、この話題に関するこれ以上の議論は求めていません。
> デバッグ実行時に環境変数を指定する点については、要はdevenv起動前に環境変数を設定するBATを書けばいいのでは?
おっしゃる事と同じ事を最初に考え、それが上手くいかないから、こうして質問をしているわけであります。
要は、バッチファイル中でdevenvを起動する前に設定した環境変数が、VB.NETのデバッグ実行時に設定が読めない、と・・・。
-
Azulean 様
リプライありがとうございます。
> この設定値は、vbproj ではなく、vbproj.user といったプロジェクトファイルとは別のユーザー設定ファイルに保存されます。
そのとおりです。申し訳ありません。少し混同しておりました。
> 通常、*.user ファイルはレポジトリにチェックインせずに管理するはずなので、個人の作業マシンのパスを入れても支障がないはずなのですが、どうなっていますか?
> // これでうまくいっても、ばっさり消える環境では毎回設定が必要ですが…。ご指摘のとおりです。やはり、少しいびつな形態での開発ですので、変なことをせずに毎回設定してやる方がいいのかもしれませんね。
大変参考になりました。
-
暫定だろうがリリース時と同じ環境にすることに変わりはありません。
リリース時にも環境変数を参照するのであれば、デバッグ環境でも環境変数を設定すべきですし、リリース時に同一ディレクトリに配置されるのであれば、デバッグ環境でも同一ディレクトリに配置すべきです。
例えばMSBuildのCopyタスクにはSkipUnchangedFilesフラグがあり不用意なコピーを削減することもできます。# 別枝ですが、製品にRuby本体が含まれるのであれば、リポジトリにも含めます。含まれないのであれば、Visual Studioのように同じパスにインストールするか環境変数から参照できるようにします。
## Visual Studioも環境変数VS90COMNTOOLS辺りの値を使ってインストール場所になるべく依存しないようにできます。 -
今更感もあるかもしれませんが。3rdparty.dllも構成管理対象の1つとして考えるなら、リポジトリ構成をこんな感じにしておいて
$/Project +--Trunc +-- Source +-- Lib
Lib配下には、3rdparty.dllやプロジェクトのビルドに必要な全てのDLLをチェックインしておき、各プロジェクトは、$Project/Trunc/Lib配下のDLLを参照するっていうのはよくやるような気もします。毎回開発環境がまっさらな状態になるというなら、たまたま古いDLLでビルドしてしまいI/Fが変わってしまうってのも防げますし。。。
-
ただ、薄々は気付いていましたが Windows での環境変数の取り扱いはちょっと感覚が違っているようで
CreateProcess という API の説明 を見てもらえればわかるかと思いますが、親プロセスの環境変数を引き継がないプロセスの立ち上げ方ができます。
なので、そういった立ち上げ方をしている部分がある場合、その処理の中で環境変数を指定する手段が用意されていないと、正攻法としては「なし」となります。// デバッグは一種のプロセス起動である。
-
CreateProcess という API の説明 を見てもらえればわかるかと思いますが、親プロセスの環境変数を引き継がないプロセスの立ち上げ方ができます。
なので、そういった立ち上げ方をしている部分がある場合、その処理の中で環境変数を指定する手段が用意されていないと、正攻法としては「なし」となります。// デバッグは一種のプロセス起動である。
プロセスに対して環境変数が渡るかということと、プロセスが渡された文字列に環境変数が含まれるか検査するというのは、別の問題だと思います。
VisualStudio の「ビルド イベント」などに設定できるパスを入力する箇所は、「マクロ」が利用できます。その代わり、環境変数は解釈しないようです。作業ディレクトリは、マクロも設定できないようです。
補足
コマンドプロンプトで環境変数「MYLIB」を「C:\」と定義します。C:\ 以外へ移動してから devenv を起動します(.sln ファイルを start コマンドで起動)。プロジェクト プロパティの「デバッグ」タブで、「作業ディレクトリ」に「%MYLIB%」を入力した場合、『入力した作業ディレクトリは存在しません。…』となりますが、「...」ボタンをクリックして表示される「作業ディレクトリの選択」ウィンドウに「%MYLIB%」を入力すると、C:\ に移動します。また、プロジェクトのコードに「Environment.GetEnvironmentVariable("MYLIB")」を入れると、デバッグ実行したときでも環境変数を取ることは出来ます。これらのことから、コマンドプロンプト(バッチファイル)から環境変数の受け渡しはできていますが、プロセスが「環境変数を表す文字列」を解釈していないと言えると思います。
これは Linux でも同じで、C 言語で chdir("$MYLIB") とコードを書いても、環境変数 MYLIB に定義したディレクトリに移動したりしません。Unix でも同じだったと思います。
Jitta@わんくま同盟
- 編集済み Jitta 2012年6月6日 13:44
-
こんにちは、矢矧 さん。
MSDN フォーラムのご利用ありがとうございます。オペレーターの山本です。
参考になる情報をいただいているように思われましたので、勝手ながら私の方で回答としてマークさせていただきました。
アドバイスくださったみなさん、情報ありがとうございます。いただいた情報の中で、解決に役立った投稿や、参考になる情報など有効な情報には回答としてマークすることをお願いしています。
今後、同じ問題でこのスレッドを参照される方にも、有効な情報を活用いただけるかと思いますので、ご協力よろしくお願いいたします。今後とも MSDN フォーラムをよろしくお願いいたします。
_____________________
日本マイクロソフト株式会社 フォーラム オペレーター 山本 春海 -
この件、その後も「DllImport が DLL を探す場所」を調べてみたのですが、Win32API の LoadLibrary 関数が探すのと同じディレクトリであるという情報がありました。ここ(MSDN フォーラム)や他の掲示板での回答としてあるだけで、正式なドキュメントには見つけることはできなかったので、URL は示しません。
ところで、最近「exeと同じフォルダにdllを配置しても「指定されたモジュールが見つかりません」のエラーになる。」という質問が上がっています。また、私自身、やはり exe と同じフォルダに dll を配置したにもかかわらず、DLL が読み込めない現象が出ました。「exeと同じ・・・」は、C++ Runtime がインストールされていなかったようです。私の方も、C++ Runtime ではありませんが、使用しているコンポーネントが足りていませんでした(見つからないと言われている DLL ではありません)。このことから、必要な何かが足りないのだけれど、本当に足りていないものとは違うものに対して「ない」というメッセージが出ているのではないかと疑います。
Jitta@わんくま同盟