Запустите файл C или C ++ как скрипт - PullRequest
25 голосов
/ 20 марта 2010

Так что это, вероятно, длинный путь, но есть ли способ запустить файл C или C ++ как скрипт? Я попробовал:

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

int main(){ return 0; }

Но там написано:

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

Ответы [ 10 ]

26 голосов
/ 20 марта 2010

Для C вы можете взглянуть на tcc , Tiny C Compiler. Запуск кода на C в качестве скрипта - одно из возможных его применений.

20 голосов
/ 18 апреля 2015

Краткий ответ:

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

Хитрость в том, что ваш текстовый файл должен быть как действующим кодом C / C ++, так и сценарием оболочки. Не забудьте exit из сценария оболочки до того, как интерпретатор достигнет кода C / C ++, или вызвать exec magic.

Запуск с chmod +x main.c; ./main.c.

Шебанг, подобный #!/usr/bin/tcc -run, не нужен, потому что Unix-подобные системы уже будут выполнять текстовый файл в оболочке.

(адаптировано с этот комментарий )


Я использовал это в своем скрипте 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;
}

Теперь, для действительно эксцентричного разработчика Java:

/*/../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(){}
17 голосов
/ 20 марта 2010
$ 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!

Команда sed берет файл .c и удаляет строку хэша. 2,$p означает печать строк от 2 до конца файла; "$@" расширяется до аргументов командной строки для скрипта runc, т.е. "main.c".

вывод sed передается в gcc. Передача - в gcc указывает ему читать из stdin, и когда вы делаете это, вы также должны указать исходный язык с помощью -x, так как у него нет имени файла для угадывания.

10 голосов
/ 20 марта 2010

Поскольку строка shebang будет передана компилятору, а # указывает на директиву препроцессора, она будет подавлена ​​#!.

Что вы можете сделать, это встроить make-файл в файл .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, окружающая make-файл, гарантирует, что препроцессор игнорирует этот фрагмент текста, а маркер EOF отмечает, где команда make должна прекратить анализ ввода.

7 голосов
/ 20 марта 2010

CINT :

CINT - интерпретатор кода C и C ++.Это полезно, например, в ситуациях, когда быстрая разработка важнее времени выполнения.Использование интерпретатора значительно сокращает цикл компиляции и компоновки, что способствует быстрой разработке.CINT делает программирование на C / C ++ приятным даже для программистов, занятых неполный рабочий день.

5 голосов
/ 26 января 2017
#!/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;
}

Это также правильно передает аргументы и код выхода.

5 голосов
/ 09 марта 2015

Вы можете оформить заказ 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, если они заканчиваются символами --:

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

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

c также использует $CFLAGS и $CPPFLAGS, если они также установлены.

4 голосов
/ 22 ноября 2018

Довольно короткое предложение будет использовать:

  • Текущий сценарий оболочки является интерпретатором по умолчанию для неизвестных типов (без шебанга или распознаваемого двоичного заголовка).
  • «#» - это комментарий в оболочке и «#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 ++, который есть в вашей системе.
  • Двоичный файл начинается с "." так что он скрыт от списка каталогов.

Проблемы:

  • Что происходит при одновременных казнях?
3 голосов
/ 20 марта 2010

Вариант Иоанна Кугельмана можно записать так:

#!/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;
}
2 голосов
/ 10 апреля 2017

Вот еще одна альтернатива:

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...