6

標準の g++ コンパイラを使用して C++ コードをコンパイルしようとしています。ただし、ファイルからコンパイルするのではなく、次のようにします。

main.cpp:

#include <iostream>

int main(){
    std::cout << "Hello World!\n";
    return 0;
}

私は次のようなことをしたいです

g++ ... "#include <iostream>\n int main(){ std::cout << \"Hello World!\n\"; return 0;}"

stackoverflow からの以前の投稿は、それを示しました

echo "int main(){}" | gcc -Wall -o testbinary -xc++ -

動作しますが、内容をパイプする必要なしにこれを行う方法があれば、それがどのように機能するかを知りたいです。

編集:

共有ライブラリを生成し、作成した関数をロードする必要がある実行時コード生成を行っています。

コンパイラに「ファイルではなくソースコードを提供します」と伝えるフラグがあると思いました。

助けてくれてありがとう!

4

6 に答える 6

7

echo "int main(){}" | gcc -Wall -o テストバイナリ -xc++ -

動作しますが、内容をパイプする必要なしにこれを行う方法があれば、それがどのように機能するかを知りたいです。

あるいは、次のように言うこともできます (例: シェルスクリプトで):

gcc -Wall -o testbinary -xc++ - << EOF
int main(){}
EOF
于 2013-07-17T15:44:19.557 に答える
2

オンザフライで C (または C++) コードを生成し、それをコンパイルしてdlopen-ing することについて言及しています。

MELT (GCC を拡張するためのドメイン固有言語)でも同じことをしています。

コードを(一時的な)ファイルに入れないようにする正当な理由はありません。生成された C または C++ の 100 万行の行でさえ、非常に高速に記述できます (MELT では、数秒未満であり、その時間のほとんどは I/O ではありません!)。はるかに遅いコンパイル (少なくとも数十秒) と、C または C++ コードを生成する目的は、特に GCC (または他のコンパイラ) によって提供される最適化を利用することです。ファイルの生成を回避すると、ほんの数ミリ秒で済みます (違いを大幅に測定することさえできません)。

したがって、ファイルを一時*.cファイルに生成し(ハッシュまたはタイムスタンプ手法を使用して一意のファイル名を生成できます)、GCCにコンパイルさせて*.so(おそらく、MELTで行うように、forkいくつかのプロセスを-ingすることにより)、それを削除しますmake一時ファイル (おそらく を使用atexit)。

ところで、この手法は、現在の PC での人間の操作と実質的に互換性があります。MELT には read-eval-print-loop があり、対話ごとに数百行の新しい C++ ファイルを生成し、それをコンパイルして dlopen-s します。これは非常に便利です!

ファイルの生成を回避するのは苦痛であり、得られるものはごくわずかです。tmpfsLinux のファイルシステム (例: )で生成することができます/tmp/。ほとんどの時間は、GCC がそのファイルをコンパイルするのに費やされます (特に、最適化などでコンパイルする場合gcc -O -fPIC -shared somefile.c -o someplugin.so)。(プログラムによって) ディスクに書き込み、GCC によってそれを読み取る (さらには C の場合は解析する) 時間はごくわずかです。GCC の-ftime-reportオプションを使用して、GCC が時間を費やしている場所を把握します。GCC にパス-Oするとすぐに解析されません。

GCC やその他の C コンパイラのバージョンによっては、stdinを入力として拒否する場合があります。一部の C コンパイラはmmap、C ソース ファイルを必要とする場合があります (たとえば、Glibc"rm"で as モードを使用するなど)。一般に、 Cは非標準であるため、ファイルfopenではないものをコンパイルするなど...ゲインは無視できるため、それを行うことは避けたほうがよいでしょう。*.c

最適化をまったく気にせず、C (C++ ではない) を非常に遅いマシン コードにすばやくコンパイルしたい場合は、代わりにライブラリを持つ tinycc (少なくとも 32 ビット マシンでは、64 ビットではバグがある可能性があります) を使用することを検討してください。文字列内のいくつかの C コードをコンパイルできます。tcc一部のlibtcc.aC コードは非常に高速に (GCC の 10 倍以上) コンパイルできますが、生成されたマシン コードのパフォーマンスは非常に悪いです (非常に遅く、最適化されていないコード)。

GCC が生成された C コードをコンパイルしたら、もちろんremove、生成されたソース コード ファイルをコンパイルできます。.so(そして、編集した後に削除することもできますdlopen)。

ところで、clang++生成された C++ ファイルをコンパイルするために使用できます。また、代わりに LLVM を使用することもできます (ファイルを使用せずに内部 LLVM 表現を生成することもできます)。

この回答も参照してください。

共有ライブラリを生成し、作成した関数をロードする必要がある実行時コード生成を行っています。

libgccjitLLVMasmjitなどの JIT コンパイルライブラリの使用も検討してください。SBCL (ほぼすべてのREPL対話でマシンコードを生成する)も調べてください。もちろん、システムに関連する呼び出し規約ABIを理解する必要があります。したがって、これelf(5)、および Drepper の論文How To Write Shared Librariesもお読みください。

于 2013-07-17T20:45:26.353 に答える
1

popen("gcc -o -xc++ -", "w"); FILE*` はどうでしょう? Gives you aが、出力は直接 GCC に送られます。

ところで、 -Wallフラグを使用しても意味がありません。それは人間の消費のためです。実際、理に-w -Wfatal-errorsかなっています。コンパイルするかしないかのどちらかです。

于 2013-07-17T21:02:22.103 に答える
0

Unix では、シェルを使用して C/C++ プログラムを作成するすべてのプロセスを自動化できます。

1.ファイルの作成(例 run_c.sh)

2.このファイルにコードを貼り付けます

#!/bin/bash

# Generate random filename
RANDOM_FILENAME=`cat /dev/urandom | tr -dc 'A-Za-z0-9' | fold -w 20 | head -n 1`
RANDOM_FILENAME=_$RANDOM_FILENAME
readonly RANDOM_FILENAME

# random filename for a C file
RANDOM_FILENAME_C=$RANDOM_FILENAME.c
readonly RANDOM_FILENAME

# catch stdin as code
CODE=$1

# names headers of the C standart language
declare -a C_STANDART_LIBRARY=('stdio' 'errno' 'assert' 'math' 'stdarg' 'stdbool' 'stdlib' 'string' 'time')

# create the C file
touch $RANDOM_FILENAME_C

# write a first line to the file
printf '// Compile C code from stdin\n\n' >> $RANDOM_FILENAME_C

# make include all headers to the file
for header in "${C_STANDART_LIBRARY[@]}"
do
    printf '#include <%s.h>\n' $header >> $RANDOM_FILENAME_C
done

# make include all headers to the file
printf "\nint main(int argc, char *argv[]) {\n" >> $RANDOM_FILENAME_C

# split the code from stdin by ';' to an array lines
IFS=';' read -r -a LINES_CODE <<< "$CODE"

# write line by line the code
for line in "${LINES_CODE[@]}"
do
    printf '%s;\n' "$line" | sed -e 's/^[[:space:]]//' | sed -e 's/^/\t/' >> $RANDOM_FILENAME_C
done

# write ending the function 'main'
printf "\treturn 0;\n}\n" >> $RANDOM_FILENAME_C

# uncomment for display the C code
# cat $RANDOM_FILENAME_C

# compile the file
gcc -Wall -std=c11 -o $RANDOM_FILENAME $RANDOM_FILENAME_C

# run programm if no errors
if [ -f "$RANDOM_FILENAME" ];
    then
    ./$RANDOM_FILENAME
fi

# rm the file with source code
rm $RANDOM_FILENAME_C
# rm the compliled file

if [ -f "$RANDOM_FILENAME" ];
    then
        rm $RANDOM_FILENAME
fi

3.このファイルを実行可能にする

$ chmod +x run_c.sh 
$ ls -l | grep run_c.sh 
-rwxr-xr-x 1 setivolkylany setivolkylany 1589 Dec 26 11:19 run_c.sh

使用法:

$ ./run_c.sh 'int a = 4; int b = 6; int c = a + b; printf("%d + %d = %d\n", a, b, c)'
4 + 6 = 10

$ ./run_c.sh 'puts("Worked");'
Worked

テスト環境

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.6 (jessie)
Release:    8.6
Codename:   jessie
$ uname -a
Linux localhost 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux

http://django-notes.blogspot.com/2013/01/compiling-c-from-stdin.htmlおよびhttps://github.com/vgvassilev/clingから着想

于 2016-12-26T09:36:47.817 に答える