質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.01%

C#コードを埋め込んで、コンパイルと実行ができるようなバッチファイルの作り方

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 240

maruine

score 1

前提・実現したいこと

一つのバッチファイルに、C#コードを埋め込んでおいて、
実行したときに「コンパイル→成果物を実行」のようなことができないか、調べています。

手法の名前が分からず、調査が難航しており、
そもそも、実現可能かどうかも分からなかった為、質問することにしました。

JScript.NET という言語向けには、下記のような実装があるので、
これと同じことをC#でも、できないか知りたいです。

@if(0)==(0) echo off&title %~n0&for /f "tokens=*" %%i in ('certutil -hashfile "%~f0" ^| find /v ":"') do (set app_hash=%%i)
set app_path=%~dp0%~n0[%app_hash%].exe
if not exist "%app_path%" (
    del "%~dp0%~n0[*].exe">nul 2>&1&setlocal enabledelayedexpansion&for /f "tokens=*" %%i in ('where /r %windir%\Microsoft.NET jsc.exe ^| sort') do (set compiler_path=%%i)
    "!compiler_path!" /nologo /out:"%app_path%" "%~f0"
)
"%app_path%" %*&exit /b %errorlevel%
@end

//! @file template.bat
//! @version 1.00r1

import System;
import System.Threading;
import System.Reflection;
import System.IO;

// エントリーポイント
Environment.Exit(function(){
    Console.WriteLine("Hello JScript.NET!!");
    Console.ReadKey();
    return 0;
}());

上記のバッチファイルが、どういった仕組みで動作しているのかは、
全貌を理解できていませんが実行すると、下記のような挙動になります。

  • @end 以下に書いたソースコードがコンパイルされて実行される
  • ソースコードに変更を加えない場合は、コンパイルがスキップされる
  • 更新があったときは、古い成果物が削除されてから実行される

発生している問題

分からないなりに格闘して、現状は下記の形になっています。

/*
@echo off&title %~n0
for /f "tokens=*" %%i in ('certutil -hashfile "%~f0" ^| find /v ":"') do (set app_hash=%%i)
set app_path=%~dp0%~n0[%app_hash%].exe
if not exist "%app_path%" (
    del "%~dp0%~n0[*].exe">nul 2>&1
    setlocal enabledelayedexpansion&for /f "tokens=*" %%i in ('where /r %windir%\Microsoft.NET csc.exe ^| sort') do (set compiler_path=%%i)
    "!compiler_path!" /nologo /out:"%app_path%" "%~f0"
)
"%app_path%" %*&exit /b %errorlevel%
*/

//! @file template.bat
//! @version 1.00r1

using System;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello C# !!");
        Console.ReadKey();
    }
}

これを実行した場合は、エラーが出ます。

'/*' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
Hello C# !!

補足情報(FW/ツールのバージョンなど)

環境は、Windows10 Pro 64bit です。

よろしくお願いします。

まとめ(追記)

最終的なコードです。

@echo off&title %~n0&setlocal enabledelayedexpansion&for /f "tokens=*" %%i in ('certutil -hashfile "%~f0"^|find /v":"') do (set app_hash=%%i)
set app_name=%~dp0%~n0[%app_hash%]&set src_path=!app_name!.cs
if not exist "%app_name%.exe" (del "%~dp0%~n0[*].*">nul 2>&1&type "%~f0"|more +5>"%src_path%"&for /f "tokens=*" %%i in ('where /r %windir%\Microsoft.NET csc.exe^|sort') do (set compiler_path=%%i)
"!compiler_path!" /nologo /out:"%app_name%.exe" "%src_path%")
"%app_name%.exe" %*&exit /b %errorlevel%

//! @file template.bat
//! @version 1.00r1

using System;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello C# !!");
        Console.ReadKey();
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Zuishin

    2019/11/08 07:36

    PowerShell を使う、あるいは csi.exe を使うのではだめなのでしょうか?

    キャンセル

  • maruine

    2019/11/08 13:09

    バッチファイルにこだわっている理由は、特にないので
    ほかの手段があれば、それでも大丈夫ですが、新たにツールをインストールするのは、避けたいです。

    用途的には、「最小限のビルド環境」として使う想定なので、
    コンパイルして成果物(.exe)が得られる形が良いです。

    PowerShell や csi.exe については、把握していなかったので、これから調べようと思います。

    キャンセル

回答 2

checkベストアンサー

+1

たぶんcsc.exeがどこかに存在していると思うのでファイルを作成して、
csc.exeでコンパイルするバッチファイルを作成すればよいと思います。

参考:
Visual Studioではなく、Windows付属のcsc.exe だけでC#実行ファイルを作る

@echo off

if exist out.cs (del out.cs)

echo using System;                                     >> out.cs
echo namespace Sample                                  >> out.cs
echo {                                                 >> out.cs
echo     class Program                                 >> out.cs
echo     {                                             >> out.cs
echo         static void Main(string[] args)           >> out.cs
echo         {                                         >> out.cs
echo             Console.WriteLine("Hello, World");    >> out.cs
echo         }                                         >> out.cs
echo     }                                             >> out.cs
echo }                                                 >> out.cs

call C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /nologo out.cs

call out.exe
@echo off

rem 11行目以降に C# のコードを記述してください

if exist out.cs (del out.cs)

type %~0 | more +11 >> %~dp0%out.cs
call C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /nologo out.cs
call out.exe

exit /b

using System;

namespace Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i <= 100; i++)
            {
                if (i % 15 == 0)
                {
                    Console.WriteLine("FizzBuzz");
                }
                else if (i % 5 == 0)
                {
                    Console.WriteLine("Buzz");
                }
                else if (i % 3 == 0)
                {
                    Console.WriteLine("Fizz");
                }
                else
                {
                    Console.WriteLine(i);
                }
            }
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/08 19:58

    追記しました。

    キャンセル

  • 2019/11/08 20:38

    バッチにしなくても out.cs を残しておいて csc out.cs じゃいけないんでしょうか?

    キャンセル

  • 2019/11/08 23:58

    > user1 さん
    今回の目的は、提示いただいた方法で完璧に対応できそうです!
    埋め込んだソースコードを出力しているので、
    ロジック自体は汎用的で他の言語でも使えそうですし、シンプルで良いと思いました。

    > Zuishin さん
    out.cs を編集して、コンパイルコマンドを打ては良いということでしょうか?
    大した手間ではないのですが、この質問の背景的には、
    コンパイルするタイプの言語をスクリプト言語的に扱えた方が、楽できそうという怠惰心から来ています。

    キャンセル

+1

csi は .NET SDK についてくるのでインストールが必要ですが、PowerShell なら入っていると思います。ただ、csc があるなら csi もあると思います。csi は C# とほぼ同じでスクリプト向けの表記を追加した C# スクリプト(*.csx)を実行するコマンドです。

PowerShell は Add-Type というコマンドで C# のソースをコンパイルできるので、ソースをヒアストリングで与えれば簡単に実装できると思います。

PowerShellスクリプト内でC#コードを書いて使う - YOMON8.NET

ただし、この方法の場合、PowerShell を再起動するとコンパイルやり直しになります。コンパイル後の実行ファイルを保存するには Microsoft.CSharp.CSharpCodeProvider または Roslyn を使います。

以下は CSharpCodeProvider を使う方法です。

PowerShell で他言語を使用する C# 編

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/08 23:15

    回答ありがとうございます。
    PowerShell と csi.exe について、軽く確認してみました。

    先に、csi.exe についてですが、
    csc がある環境でも、Visual Studio をインストールしていないと、csi.exe は使えなさそうだったので、
    興味は引かれましたが一旦除外しました。(csc.exe は、Windowsにプリインストールされています。)

    PowerShell の方は、リンク先のソースをもとに少し変更を加えて.exe が出力できることを確認しました。
    .ps1がセキュリティ周りの仕様で、直接実行できないようになっていることに目をつぶれば、
    この方法で、問題が解決しそうです。

    ただ今まで、サクラエディタを使っていたので、「Ctrl+B」で直接実行できない点が気になりました。
    「PowerShell ISE」という標準のエディタ(IDE?)を使えば、ショートカットで実行できますが...

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる