0
0

Node.jsのexpressでc言語のプログラムをRenderで実行

Posted at

はじめに

とあるプログラムがC言語で書かれていて、それをwebシステムとしてnodeで実行したいと思ったのでやり方を調べました。整理すると、大したことはないです。

概要

準備

  1. c言語のソースをコンパイルして、モジュールを作成
  2. Webサーバーとしてexpressを起動する

アクセス時

  1. expressのサーバー処理がモジュールをキックし、標準出力を得る
  2. 標準出力を元にクライアントへ返す

作ったソース

結果を一応貼っておくと、↓こういう文字を返すだけのwebシステムですw
image.png

詳細

全体

フォルダ構成
image.png
役割は、scriptsがc言語関係で、ソースとビルド用のスクリプト。serverexpressのソースです。
ちなみに最終的に、c言語のモジュールをserverの下へ置きます。

c言語のソース

hello.c
#include <stdio.h>

int main() {
    printf("Hello, World!(c言語より!)\n");
    return 0;
}

なんでもいいんです。標準出力すれば。
日本語のやり取りができることの確認もしてます。

c言語ソースのコンパイル

Render上でビルドしてほしいので、package.jsonで次のように設定しておきます。

package.json(の一部)
  "scripts": {
    "start": "node ./server/app.js",
    "build": "npm install && node ./scripts/build-with-c.js"
  },

Renderの設定で、ビルドはnpm run build、起動はnpm run startとすることを想定しています。

build-with-c.js
const { exec } = require('child_process');
const { copyFileSync } = require('fs');
const { platform } = require('os');

// コンパイルするCプログラムのパスと出力ファイル名
const scriptsDirName = "scripts";
const inputFilePath = `./${scriptsDirName}/hello.c`;
const outputFileName = 'hello' + (platform() === 'win32' ? '.exe' : '');
const outputFilePath = `./${scriptsDirName}/${outputFileName}`;
const buildOutputFilePath = `./server/${outputFileName}`;

// Cプログラムをコンパイル
exec(`gcc ${inputFilePath} -o ${outputFilePath}`, (compileError) => {
    if (compileError) {
        console.error(`コンパイルエラー: ${compileError}`);
        process.exit(1);
    }
    console.log('Cプログラムのコンパイル成功');

    // コンパイルしたプログラムをビルドディレクトリにコピー
    copyFileSync(outputFilePath, buildOutputFilePath);
    console.log('ビルドディレクトリにhelloをコピー');
});

ファイル名をごちゃごちゃやっているのは、開発環境ではexeにしたかったというだけです。
本筋は、execgccを使ってコンパイルし、できたモジュールをcopyFileSync./server/へコピーしてます。
gccは、Renderが持ってます。

expressサーバー

app.js
const express = require("express")
const path = require("path");
const { exec } = require("child_process");


const app = express()
const port = 3000

app.get('/', (req, res) => {
    const outputFileName = 'hello' + (process.platform === 'win32' ? '.exe' : '');
    const buildOutputPath = path.join(__dirname, outputFileName);

    exec(buildOutputPath, (runError, stdout, stderr) => {
        if (runError) {
            console.error(`実行エラー: ${runError}`);
            return res.status(500).send(`実行エラー: ${runError}`);
        }
        if (stderr) {
            console.error(`標準エラー出力: ${stderr}`);
            return res.status(500).send(`標準エラー出力: ${stderr}`);
        }
        res.send(stdout);
    });
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

execで、出力したファイルを非同期で実行し、エラーなく進んだら、その標準出力stdout/の戻り値にしてます。

あ、以上でした。この結果が、最初にも貼った下記のもの。日本語も渡ってます。

image.png

おわりに

JavaScriptでひとまずできました。Renderはほんと便利で感謝です。

つぎはTypeScriptでやってみます。
実は最初TypeScriptでやったらいろいろな問題が出たのですが、問題の切り分けが大変でした。(そのときのアプリ名がapp-c-lang。)そのため先にJavaScriptでやって足掛かりを作ってみた次第です。JavaScriptでできた上でのTypeScriptなら、TypeScript特有の手続きは何なのかっていうことが分かりやすいかなと思って。

0
0
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
0
0