programing

C 또는 C++ 파일을 스크립트로 실행

bestprogram 2023. 9. 9. 09:48

C 또는 C++ 파일을 스크립트로 실행

그래서 이것은 아마도 긴 시도일 것입니다만, C 또는 C++ 파일을 스크립트로 실행할 수 있는 방법이 없을까요?노력했습니다.

#!/usr/bin/gcc main.c -o main; ./main

int main(){ return 0; }

하지만 이렇게 적혀있습니다.

./main.c:1:2: error: invalid preprocessing directive #!

단답형:

//usr/bin/clang "$0" && exec ./a.out "$@"
int main(){
    return 0;
}

비결은 텍스트 파일이 유효한 C/C++ 코드와 셸 스크립트여야 한다는 것입니다.기억하기exit하거나 C/C++ 코드를 호출합니다.exec요술을

와 함께 chmod +x main.c; ./main.c.

그녀는 쾅.#!/usr/bin/tcc -run유닉스 계열 시스템들은 이미 셸 내에서 텍스트 파일을 실행할 것이기 때문에 필요하지 않아도 됩니다.

( 코멘트에서 삭제)


C++ 스크립트에서 사용했습니다.

//usr/bin/clang++ -O3 -std=c++11 "$0" && ./a.out; exit
#include <iostream>
int main() {
    for (auto i: {1, 2, 3})
        std::cout << i << std::endl;
    return 0;
}

컴파일 라인이 너무 커지면 이 일반적인 이전 C 코드가 보여주는 것처럼 전처리기( 답변에서 채택)를 사용할 수 있습니다.

#if 0
    clang "$0" && ./a.out
    rm -f ./a.out
    exit
#endif
int main() {
    return 0;
}

물론 실행 파일을 캐시할 수 있습니다.

#if 0
    EXEC=${0%.*}
    test -x "$EXEC" || clang "$0" -o "$EXEC"
    exec "$EXEC"
#endif
int main() {
    return 0;
}

자, 정말 별난 자바 개발자를 위해:

/*/../bin/true
    CLASS_NAME=$(basename "${0%.*}")
    CLASS_PATH="$(dirname "$0")"
    javac "$0" && java -cp "${CLASS_PATH}" ${CLASS_NAME}
    rm -f "${CLASS_PATH}/${CLASS_NAME}.class"
    exit
*/
class Main {
    public static void main(String[] args) {
        return;
    }
}

D 프로그래머들은 구문을 깨지 않고 텍스트 파일의 처음에 셰뱅을 넣기만 하면 됩니다.

#!/usr/bin/rdmd
void main(){}

참조:

C의 경우 Tiny C 컴파일러인 tcc를 살펴볼 수 있습니다.C 코드를 스크립트로 실행하는 것은 가능한 용도 중 하나입니다.

$ cat /usr/local/bin/runc
#!/bin/bash
sed -n '2,$p' "$@" | gcc -o /tmp/a.out -x c++ - && /tmp/a.out
rm -f /tmp/a.out

$ cat main.c
#!/bin/bash /usr/local/bin/runc

#include <stdio.h>

int main() {
    printf("hello world!\n");
    return 0;
}

$ ./main.c
hello world!

는 seds 은 을 합니다 합니다 를 합니다..c파일을 저장하고 해시뱅 라인을 제거합니다.2,$p줄하는 것을 합니다.일줄를 2는다을에다을는st2일s를;에"$@"합니다. 행를로 runc다즉 . ,"main.c".

sed 은 gcc 됩니다 로 의 됩니다 은 에 파이프됩니다.합격-하고, 할때 gcc을 stdin고게은한할스다를때서는geheo야e를eogtycmoncntsodud,n한-x파일 이름이 없기 때문입니다.

shebang 라인은 컴파일러로 전달될 것이고 #는 전처리기 지시를 나타내기 때문에 #!에서 질식할 것입니다.

당신이 할 수 있는 일은 makefile을 .c 파일에 내장하는 것입니다 (이 xkcd 스레드에서 설명된 것처럼).

#if 0
make $@ -f - <<EOF
all: foo
foo.o:
   cc -c -o foo.o -DFOO_C $0
bar.o:
   cc -c -o bar.o -DBAR_C $0
foo: foo.o bar.o
   cc -o foo foo.o bar.o
EOF
exit;
#endif

#ifdef FOO_C

#include <stdlib.h>
extern void bar();
int main(int argc, char* argv[]) {
    bar();
    return EXIT_SUCCESS;
}

#endif

#ifdef BAR_C
void bar() {
   puts("bar!");
}
#endif

#if 0 #endif, 명령이 해야 하는 합니다. makefile은 make file과 make file의 parsing input, EOF는 make file과 make file의 parsing input을 표시합니다.

CINT:

CINT는 C와 C++ 코드의 인터프리터입니다.실행 시간보다 빠른 개발이 더 중요한 상황에 유용합니다.인터프리터를 사용하면 컴파일 및 링크 주기가 크게 단축되어 빠른 개발이 용이합니다.CINT는 시간제 프로그래머도 C/C++ 프로그래밍을 즐길 수 있습니다.

이 점을 염두에 두고 설계된 ryanmjacobs/c를 확인해 보는 것이 좋습니다.좋아하는 컴파일러 주위의 래퍼 역할을 합니다.

#!/usr/bin/c
#include <stdio.h>

int main(void) {
    printf("Hello World!\n");
    return 0;
}

사용할 때의 좋은 점c예를 들어 어떤 컴파일러를 사용할지 선택할 수 있습니다.

$ export CC=clang
$ export CC=gcc

따라서 좋아하는 최적화도 모두 얻을 수 있습니다!그요를 .tcc -run!

플래그를 할 수 . shebang이 shebang으로 되는 한 shebang에 컴파일러 플래그를 추가할 수 . 그것들이 종료되는 한.--캐릭터:

#!/usr/bin/c -Wall -g -lncurses --
#include <ncurses.h>

int main(void) {
    initscr();
    /* ... */
    return 0;
}

c도를 합니다.$CFLAGS그리고.$CPPFLAGS그것들도 세팅이 되어 있다면요.

#!/usr/bin/env sh
tail -n +$(( $LINENO + 1 )) "$0" | cc -xc - && { ./a.out "$@"; e="$?"; rm ./a.out; exit "$e"; }

#include <stdio.h>

int main(int argc, char const* argv[]) {
    printf("Hello world!\n");
    return 0;
}

이것은 인수와 종료 코드도 적절하게 전달합니다.

상당히 짧은 제안은 다음을 활용할 수 있습니다.

  • 현재 셸 스크립트는 알 수 없는 유형(셰뱅 또는 인식 가능한 이진 헤더 없음)의 기본 인터프리터입니다.
  • "#"은 셸의 주석이고 "#if 0"은 코드를 비활성화합니다.

    #if 0
    F="$(dirname $0)/.$(basename $0).bin"
    [ ! -f $F  -o  $F -ot $0 ] && { c++ "$0" -o "$F" || exit 1 ; }
    exec "$F" "$@"
    #endif
    
    // Here starts my C++ program :)
    #include <iostream>
    #include <unistd.h>
    
    using namespace std;
    
    int main(int argc, char **argv) {
        if (argv[1])
             clog << "Hello " << argv[1] << endl;
        else
            clog << "hello world" << endl;
    }
    

그러면 가능합니다.chmod +x.cpp 파일 및 그 다음./run.cpp.

  • 컴파일러의 플래그를 쉽게 지정할 수 있습니다.
  • 이진 파일은 소스와 함께 현재 디렉터리에 캐시되며 필요할 때 업데이트됩니다.
  • 됩니다: 는 으로 됩니다 됩니다 으로 는 ../run.cpp Hi
  • 다시 사용하지 않습니다.a.out폴더에 파일을 수 하기 위해 , 에 의 을 할 할 을 에 .
  • 시스템에 있는 모든 c++ 컴파일러를 사용합니다.
  • 바이너리는 디렉토리 목록에서 숨기도록 "."로 시작합니다.

문제:

  • 동시 실행 시 어떻게 됩니까?

존 쿠겔만의 변주는 다음과 같이 쓸 수 있습니다.

#!/bin/bash
t=`mktemp`
sed '1,/^\/\/code/d' "$0" | g++ -o "$t" -x c++ - && "$t" "$@"
r=$?
rm -f "$t"
exit $r


//code
#include <stdio.h>

int main() {
    printf("Hi\n");
    return 0;
}

여기에 또 다른 대안이 있습니다.

#if 0
TMP=$(mktemp -d)
cc -o ${TMP}/a.out ${0} && ${TMP}/a.out ${@:1} ; RV=${?}
rm -rf ${TMP}
exit ${RV}
#endif

#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("Hello world\n");
  return 0;
}

저는 이 질문이 최근에 나온 질문이 아니라는 것을 알지만, 어쨌든 저는 제 대답을 혼합하기로 결정했습니다.Clang과 LLVM을 사용하면 중간 파일을 작성하거나 외부 도우미 프로그램/스크립트를 호출할 필요가 없습니다.(클랑/클랑++/lli 제외)

clang/clang++ tolli의 출력을 파이프로 연결하면 됩니다.

#if 0
CXX=clang++
CXXFLAGS="-O2 -Wall -Werror -std=c++17"
CXXARGS="-xc++ -emit-llvm -c -o -"
CXXCMD="$CXX $CXXFLAGS $CXXARGS $0"
LLICMD="lli -force-interpreter -fake-argv0=$0 -"
$CXXCMD | $LLICMD "$@" ; exit $?
#endif

#include <cstdio>

int main (int argc, char **argv) {
  printf ("Hello llvm: %d\n", argc);
  for (auto i = 0; i < argc; i++) {
    printf("%d: %s\n", i, argv[i]);
  }
  return 3==argc;
}

그러나 위의 내용은 c/c++ 스크립트에서 stdin을 사용할 수 없습니다.bash가 셸인 경우 stdin을 사용하기 위해 다음을 수행할 수 있습니다.

#if 0
CXX=clang++
CXXFLAGS="-O2 -Wall -Werror -std=c++17"
CXXARGS="-xc++ -emit-llvm -c -o -"
CXXCMD="$CXX $CXXFLAGS $CXXARGS $0"
LLICMD="lli -force-interpreter -fake-argv0=$0"
exec $LLICMD <($CXXCMD) "$@"
#endif

#include <cstdio>

int main (int argc, char **argv) {
  printf ("Hello llvm: %d\n", argc);
  for (auto i = 0; i < argc; i++) {
    printf("%d: %s\n", i, argv[i]);
  }
  for (int c; EOF != (c=getchar()); putchar(c));
  return 3==argc;
}

shebang(#!)을 유지해야 한다는 몇 가지 제안이 있지만 gcc 컴파일러에서는 불법입니다.그래서 여러 가지 해결책들이 그것을 잘라냅니다.또한 c 코드가 잘못된 경우에 대한 컴파일러 메시지를 수정하는 전처리기 지시문을 삽입할 수 있습니다.

#!/bin/bash
#ifdef 0 
xxx=$(mktemp -d)
awk 'BEGIN 
 { print "#line 2 \"$0\""; first=1; } 
 { if (first) first=0; else print $0 }' $0 |\
g++ -x c++ -o ${xxx} - && ./${xxx} "$@"
rv=$?
\rm ./${xxx}
exit $rv
#endif
#include <iostream>
int main(int argc,char *argv[]) { 
  std::cout<<"Hello world"<<std::endl; 
}

이전 답변에서 말씀드린 것과 같이,tcc당신의 컴파일러로써, 당신은 shebang을 넣을 수 있습니다.#!/usr/bin/tcc -run소스 파일의 첫 줄로 표시됩니다.

그러나 이와 관련하여 작은 문제가 있습니다: 동일한 파일을 컴파일하고 싶다면, 컴파일하고 싶다면,gcc던지다error: invalid preprocessing directive #!(tccshebang을 무시하고 잘 컴파일 할 것입니다).

만약 당신이 아직도 다음과 같이 컴파일해야 합니다.gcc하나의 해결책은 사용하는 것입니다.tailshebang 라인을 소스 파일에서 잘라낸 후 pipeing을 수행하는 명령.gcc:

tail -n+2 helloworld.c | gcc -xc -

모든 경고 및/또는 오류는 한 줄씩 꺼집니다.

파일이 shebang으로 시작하는지 확인하는 bash 스크립트를 만들어 자동화할 수 있습니다.

if [[ $(head -c2 $1) == '#!' ]]
then
  tail -n+2 $1 | gcc -xc -
else
  gcc $1
fi

직접 호출하는 대신 소스를 컴파일하는 데 사용합니다.gcc.

Pedro가 솔루션에 대해 설명해 준 덕분에 공유하고 싶었을 뿐입니다.#if 0트릭, 저는 TCC(Sugar C)에서 포크를 업데이트하여 모든 예제를 shebang으로 호출할 수 있도록 하였으며, 마지막으로 IDE에서 소스를 찾을 때 오류가 없습니다.

이제 코드가 아름답게 표시됩니다.clangd프로젝트 소스에 대한 VS Code.표본 첫 번째 선은 다음과 같습니다.

#if 0
  /usr/local/bin/sugar `basename $0` $@ && exit;
  // above is a shebang hack, so you can run: ./args.c <arg 1> <arg 2> <arg N>
#endif

보다 램 하는 것이었습니다.-run지시).

프로젝트는 https://github.com/antonioprates/sugar 에서 확인할 수 있습니다.

실행 파일로 실행하기 위한 다양한 언어에 대한 해시뱅/쉬뱅 예제

컴파일된 언어도 실행 가능한 스크립트인 것처럼 실행할 수 있습니다.

이것을 가능하게 하기 위해 제가 프로그램의 맨 위에 있는 첫 번째 줄로 사용하고 싶은 필요한 해시뱅 줄들은 다음과 같습니다.

  1. C의 경우 (컴파일화) (기술적으로는 아래에 명시한 대로 gnu C):

    ///usr/bin/env ccache gcc -Wall -Wextra -Werror -O3 -std=gnu17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit
    
  2. C++(컴파일)경우(기술적으로는 아래에 명시한 대로 gnu++):

    ///usr/bin/env ccache g++ -Wall -Wextra -Werror -O3 -std=gnu++17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit
    

    및 의 C ≥ C++ ≥ C,ccache당신의 컴파일이 좀 더 효율적이 되도록 도와줍니다.와 함께 하기sudo apt update && sudo apt install ccache.

  3. For Go (컴파일) (골랑)

    ///usr/bin/env go run "$0" "$@"; exit
    

    ...그리고 위의 행에 대한 자세한 설명은 여기에서 제 다른 답변을 참조하십시오.적절한 고쉐방 라인은 무엇입니까?

  4. 녹용(컴파일)

    ///usr/bin/env rustc "$0" -o /tmp/a && /tmp/a "$@"; exit
    

    추가 도움말:

    1. 러스트 설치 : https://www.rust-lang.org/tools/install
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
      
    2. "Rusty By Example" 공식 온라인 책 "hello world" 예제: https://doc.rust-lang.org/stable/rust-by-example/hello.html
  5. Bash용(해석)

    #!/usr/bin/env bash
    
  6. Python의 경우(해석)

    #!/usr/bin/env python3
    

로 :time네가 원한다면.

컴파일 시간을 측정하려면 다음을 추가합니다.bash -c time해시-뱅의 시작 부근에, 다음과 같이.다음은 C++의 예입니다. (기술적으로는 gnu++17입니다.)

///usr/bin/env bash -c time ccache g++ -Wall -Wextra -Werror -O3 -std=gnu++17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit

이제 파일을 실행 파일로 표시하고 직접 실행할 수 있습니다!

# make executable
chmod +x hello_world.c      # C
chmod +x hello_world.cpp    # C++
chmod +x hello_world.go     # Go
chmod +x hello_world.rs     # Rust
chmod +x hello_world.sh     # Bash
chmod +x hello_world.py     # Python

# run
cd path/to/dir/containing/these/files
./hello_world.c      # C
./hello_world.cpp    # C++
./hello_world.go     # Go
./hello_world.rs     # Rust
./hello_world.sh     # Bash
./hello_world.py     # Python

참조:

  1. eRCaGuy_hello_world repo에서 다양한 언어에 대한 shebang의 위의 몇 가지 용도를 보고 실행할 수 있습니다.
    1. 이 된 을 을 찾습니다.language/hello_world*아니면language/hello*.
    2. Ex: C: c/hello_world_extra_basic.c
  2. 까지.//?
  3. [내 대답] 적절한 고쉐방 대사는?
  4. 저도 제 블로그에 올려놨습니다. https://gabrielstaples.com/hash-bangs-to-run-compiled-languages-as-executables/

언급URL : https://stackoverflow.com/questions/2482348/run-c-or-c-file-as-a-script