Exe-Datei erstellen aus C-Programm mit gcc


#1

Hallo.

Ich programmiere in der Schule gerade C und kompiliere das dann mit gcc. Hab auf meinem Windows-Rechner auch gcc installiert, sodass ich mit Netbeans nun nicht nur Java sondern auch C programmieren kann. Mein derzeitiges Programm läuft in der NB-Konsole auch problemlos, nur im Gegensatz zu Java verstehe ich das builden bei c nicht. Ob ich auf Build, Clean & Build oder Build Package klicke, die exe die am Ende erzeugt wird wird nciht ausgeführt mit der Meldung, cygwin1.dll würde fehlen. Füge ich diesen manuell in den Ordner mit der exe, kommt ein anderer Fehler…

Wie normalerweise wenn die dll fehlerhaft is…

Wie mache ich jetz aus meinen Dateien eine (Aus der Kommandozeile) ausführbare exe Datei? Muss aus der Kommandozeile ausführbar sein, da es ein reines Konsolenprogramm is ohne GUI etc


#2

Nur ein schneller Tipp: Probier’ das ganze mal im Release-Modus zu komplilieren, und schau’, ob es dann mit der cygwin DLL zusammen funktioniert. Wenn’s das nicht ist… braucht man vermutlich mehr Infos (welche Dateien dazugelinkt werden etc). Hab’ aber noch nie was mit C+NetBeans gemacht (nur Visual Studio).


#3

Ich habe von der Schule ein Microsoft Imagine-Konto erhalten, wodurch ich mit auch problemlos Visual Studio installieren könnte, ich fand es aber praktischer nur 1 IDE für alles benutzen, wenns denn möglich is, allein schon weil man sich so dran gewöhnt hat.

Kompilier ich es im Release-Modus ist es exakt das selbe… Das Programm arbeitet mit 1 txt-Datei und die .c Datei mit der main. Die includes sind diese:

#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <locale.h>
#include <unistd.h>```

Die komplette C-Datei, falls benötigt, schaut so aus:
[SPOILER]```/* 
 * File:   main.c
 * Author: Andy
 *
 * Created on 14. Februar 2017, 20:21
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <locale.h>
#include <unistd.h>

void verschluesseln(char* pin) {
    int i;
    for (i = 0; i < strlen(pin); i++) {
        pin** = pin** + 128;
    }
}

void entschluesseln(char* pin) {
    int i;
    for (i = 0; i < strlen(pin); i++) {
        pin** = pin** - 128;
    }
}

void dateiSchreiben(FILE* datei, float kontostand, bool sperre, char* geheimzahl, char* username, int stelle) {
    datei = fopen("usernames.txt", "rw+");
    FILE* tempDatei = tmpfile();
    char temp[100];
    verschluesseln(geheimzahl);

    int i;
    for (i = 0; fscanf(datei, "%s", &temp) == 1; i++) {
        if (i != stelle) {
            fprintf(tempDatei, "%s
", temp);
        } else {
            fprintf(tempDatei, "%g;%i;%s;%s
", kontostand, sperre, geheimzahl, username);
        }
    }

    fseek(datei, 0, SEEK_SET);
    fseek(tempDatei, 0, SEEK_SET);

    while (fscanf(tempDatei, "%s", &temp) == 1) {
        fprintf(datei, "%s
", temp);
    }

    fclose(datei);
    fclose(tempDatei);
}

int main(int argc, char** argv) {
    float kontostand;
    int i, menuEingabe = 0, abhebenEingabe, stelle;
    bool sperre, hierSperre = false, userFound = false;
    char usernameEingabe[100], temp[200];
    char* geheimEingabe;
    char* pinVeri;
    char* neuePin1;
    char* neuePin2;
    char* geheimzahl;
    char* usernameDatei;
    FILE* fp_usernames = fopen("usernames.txt", "r");

    setlocale(LC_NUMERIC, "de_DE.UTF-8");

    if (fp_usernames != NULL) {
        printf("Bitte geben Sie den Benutzernamen ein: ");
        scanf("%s", &usernameEingabe);
        for (stelle = 0; fscanf(fp_usernames, "%f;%i;%s", &kontostand, &sperre, &temp) == 3; stelle++) {
            //            aufteilen2(temp, geheimzahl, usernameD);
            geheimzahl = strtok(temp, ";");
            entschluesseln(geheimzahl);
            usernameDatei = strtok(NULL, ";");
            if (strcmp(usernameEingabe, usernameDatei) == 0) {
                userFound = true;
                break;
            }
            fclose(fp_usernames);
        }

        if (!userFound) {
            printf("Benutzername nicht vorhanden!
");
        } else {
            for (i = 1; i <= 3 && !sperre; i++) {
                geheimEingabe = getpass("Bitte geben Sie die Geheimzahl ein: ");
                if (strcmp(geheimzahl, geheimEingabe) != 0 && !sperre) {
                    printf("Falsche PIN! Noch %i Versuche bis zur Sperrung!
", 3 - i);
                    if (i == 3) {
                        sperre = hierSperre = true;
                        printf("Ihr Konto wurde gesperrt!
");
                        dateiSchreiben(fp_usernames, kontostand, sperre, geheimzahl, usernameDatei, stelle);
                    }
                } else {
                    break;
                }
            }

            if (!hierSperre) {
                if (sperre) {
                    printf("Ihr Konto ist gesperrt!
");
                } else {
                    printf("Herzlich Willkommen %s!
", usernameEingabe);
                    while (menuEingabe != 5) {
                        printf("Menu:
Kontostand (1):
Geld auszahlen (2):
Geld einzahlen (3)
PIN ändern (4)
Beenden (5):
");
                        scanf("%i", &menuEingabe);
                        switch (menuEingabe) {
                            case 1: printf("Ihr Kontostand beträgt %'.2f Euro.
", kontostand);
                                break;
                            case 2:
                                printf("Wie viel Euro möchten Sie abheben? ");
                                scanf("%i", &abhebenEingabe);
                                if (abhebenEingabe > kontostand) {
                                    printf("Negative Kontostände nicht zulässig!
");
                                } else if (abhebenEingabe % 5 != 0) {
                                    printf("Der Betrag muss durch 5 Euro teilbar sein! Münzausgabe nicht unterstützt!
");
                                } else {
                                    kontostand -= abhebenEingabe;
                                    dateiSchreiben(fp_usernames, kontostand, sperre, geheimzahl, usernameDatei, stelle);
                                    printf("Es wurden erfolgreich %'i Euro von Ihrem Konto abgebucht! Der neue Kontostand beträgt nun %'.2f Euro!
", abhebenEingabe, kontostand);
                                }
                                break;
                            case 3:
                                printf("Wie viel Geld wollen Sie einzahlen? ");
                                scanf("%i", &abhebenEingabe);
                                kontostand += abhebenEingabe;
                                dateiSchreiben(fp_usernames, kontostand, sperre, geheimzahl, usernameDatei, stelle);
                                printf("Es wurden erfolgreich %'i Euro auf Ihr Konto gebucht! Der neue Kontostand beträgt nun %'.2f Euro!
", abhebenEingabe, kontostand);
                                break;
                            case 4:
                                pinVeri = getpass("Bitte geben Sie zur Verifizierung die alte PIN ein: ");
                                if (strcmp(geheimzahl, pinVeri) == 0) {
                                    bool gleich = false;
                                    while (!gleich) {
                                        neuePin1 = getpass("Bitte geben Sie die neue PIN ein: ");
                                        neuePin2 = getpass("Bitte geben Sie die neue PIN noch einmal ein: ");
                                        if (strcmp(neuePin1, neuePin2) != 0) {
                                            printf("Die neuen PINs stimmen nicht überein! Bitte erneut eingeben!
");
                                        } else if (strlen(neuePin1) != 4) {
                                            printf("Die PIN muss 4-stellig sein!
");
                                        } else {
                                            gleich = true;
                                            geheimzahl = neuePin1;
                                        }
                                    }
                                    dateiSchreiben(fp_usernames, kontostand, sperre, geheimzahl, usernameDatei, stelle);
                                    printf("Die PIN wurde erfolgreich geändert!
");
                                }
                                break;
                        }
                    }
                }
            }
        }

        fclose(fp_usernames);
    } else {
        printf("Benuternamen-Datei konnte nicht geöffnet werden!
");
    }

    return (EXIT_SUCCESS);
}```[/SPOILER]

Edit: Der C-Tag ist ja mal komplett fürn Hintern...

#4

Ja, der C-Code-Formatter war mal kaputt, und hat bei irgendwelchen absurden Code-Snippets die Seite zerhauen. “java” oder “code” wären wohl OK.

Hab’s gerade mal probiert: Was passiert denn bei dir, wenn du einfach
gcc main.c
eintippst?

Dann sollte eine a.exe entstehen. Beim Versuch, die zu starten, sollte die Fehlermeldung mit der Fehlenden cygwin1.dll kommen, aber wenn man die dazukopiert, sollte es gehen (d.h. “Benuternamen-Datei konnte nicht ge▒ffnet werden!” … (BenutZer…)

Ziemlich geraten: Könnte das ein 32/64bit-Problem sein? Ich nehme an, du hast ein 64bit-System UND auch die 64bit Cygwin, oder?

Kann man sich ansehen, welche Kommandozeile NetBeans beim Compilieren ausführt?


#5

Wie Marco13 bereits schrieb, vielleicht Visual Studio in Erwägung ziehen.

Sonst ist hier noch eine Anleitung 1,
und hier noch eine Anleitung 2.

Insbesondere sieht man auch eine Ausgabe: https://youtu.be/FDJ7YhMzsXw?t=5m29s .

Klick dich auch mal durch die Konfiguration des Projekts durch…


#6

@Marco13 : Das führt NB aus beim builden:

cd ‘C:\Users\Andy\Documents\NetBeansProjects\Bankomat’
D:\cygwin64\bin\make.exe -f Makefile CONF=Release
“/usr/bin/make” -f nbproject/Makefile-Release.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory ‘/cygdrive/c/Users/Andy/Documents/NetBeansProjects/Bankomat’
“/usr/bin/make” -f nbproject/Makefile-Release.mk dist/Release/Cygwin-Windows/bankomat.exe
make[2]: Entering directory ‘/cygdrive/c/Users/Andy/Documents/NetBeansProjects/Bankomat’
mkdir -p build/Release/Cygwin-Windows
rm -f “build/Release/Cygwin-Windows/main.o.d”
gcc -c -O2 -MMD -MP -MF “build/Release/Cygwin-Windows/main.o.d” -o build/Release/Cygwin-Windows/main.o main.c
mkdir -p dist/Release/Cygwin-Windows
gcc -o dist/Release/Cygwin-Windows/bankomat build/Release/Cygwin-Windows/main.o
make[2]: Leaving directory ‘/cygdrive/c/Users/Andy/Documents/NetBeansProjects/Bankomat’
make[1]: Leaving directory ‘/cygdrive/c/Users/Andy/Documents/NetBeansProjects/Bankomat’

wenn ich es per Konsole so machen will wie in der Schule (gcc main.c) klappts hier iwie nich. Kommt ne Fehlermeldung das ne lib nich gefunden wurde.

Ist auch 64bit gcc (x86_64)


#7

Hämoment… dem Prompt nach sieht das aus, als würdest du das an der DOS-Kommandozeile eingeben?!
(Oder hast du das Cygwin Terminal irgendwie umkonfiguriert?)

Im Terminal (also dem, was man mit
C:\cygwin64\bin\mintty.exe -
aufmacht) sollte das eigentlich gehen…


#8

habe das normale kommandofenster benutzt. in mintty sagt er nur gcc: command not found…


#9

Ehrlich gesagt bin ich da auch nicht so firm, aber … beachte das - hinter dem Aufruf: Das braucht er (damit er eine “echte” shell aufmacht).

EDIT: Nebenbei: Cygwin hatte bei mir bei der Installation direkt ein Desktop-Icon dafür erstellt…


#10

Bei mir nicht, hab kein Symbol zu iwas aus dem Ding aufm Desktop. Bin mir nichmal sicher ob ich das überhaupt installiert hab oder einfach was entpackt habe, habs aber von der offiziellen Seite.

So, habs nun folgendermaßen kompiliert:

Und er erzeugt mir wieder die exe. Nur wie führe ich die nun aus? Hab die dll dazugepackt, selbe Fehlermeldung will ich sie im normalen CMD-Fenster öffnen

Edit: Aso, alles im Mintty. Okay, schonmal ein Anfang. Nur das Problem ist, ich wollte die exe vorangig erzeugen, damit ich sie anderen geben kann und sie diese einfach in ihrer Kommandozeile benutzen können, ohne selbst Cygwin installiert zu haben. Wenn ich mintty dafür brauche, geht das ja schonmal nich. Aber das Programm läuft problemlos darin (wenn ich die usernames.txt noch dazukopiert habe)
Linux ist was das angeht einfach so viel angenehmer… da mach ich einfach “gcc xxx.c -o xxx && ./xxx” und es läuft, egal auf welchen Rechner ich das schiebe


#11

Ich würde gerne etwas geordneter und fokussierter antworten, muss aber sagen, dass das bisher eher der Versuch war, das ganze einzugrenzen:

Wenn man im Mintty die .exe compiliert hat, dann sollte man die auch außerhalb des Mintty (also in einem beliebigen Prompt) starten können. (Wenn die DLL dabei ist).


#12

Das ist ja das Problem: Das geht ja nich, kommt die gleiche Fehlermeldung wie bei der exe aus NetBeans


#13

Hmsorry. Ich müßte wohl selbst mal NetBeans mit dem GCC-Support installieren. So … ist das eher ein “geführtes Rumprobieren” (und ich hoffe, dass ich dich nicht in komplett absurde Richtungen leite).

Was passiert denn, wenn du am Mintty die Befehle ausführst, die NB da so auflistet?


gcc -c -O2 -MMD -MP -MF ..

(Ich müßte jetzt erst nachsehen, was genau die M-Parameter machen, aber irgendwo MUSS ja der Unterschied sein…)

Ggf. auch mal die Makefile posten. Vielleicht stolpert jemand drüber, der sich damit besser auskennt. (Das letzte mal, dass ich C von Hand an der Konsole (mit Makefile) compiliert habe, ist >10 Jahre her, und war ohne die Netbeans/Cygwin-Schicht dazwischen…)


#14

Also das Problem liegt ja nich direkt an Netbeans, da die exe aus mintty ja wie gesagt auch nicht funktioniert außerhalb von mintty. In Mintty funktionieren beide exen problemlos. Ich probier die nb-befehle aber mal

Edit: Jetz funktioniert auf einmal doch… Hab die dll einfach nochmal rausgelöscht und wieder neu reinkopiert und tada, nun funktionierts auch im cmd


#15

Das “kann eigentlich nicht sein” (aber weil eigentlich eigentlich kein Wort ist, kann man es eigentlich weglassen).

Wenn’s nun geht ist’s zwar gut, aber dieses nagend-unbehagliche Gefühl, irgendwas nicht richtig verstanden zu haben (und dass das Problem ggf. wieder auftritt, und man dann nicht weiß, wie man es systematisch lösen kann), bleibt…


#16

Also die dll die ich davor benutzt habe war ausm Internet, die mit der es geht aus dem cygwin-Ordner. Mit der ausm Ordner gings dann


#17

Das erklärt alles.


#18
  1. man nimmt nicht irgendwas aus dem Internet. Der GCC hat einen anderen Sprungpunkt in der EXE angelegt, als in der Internet-DLL vorhanden war.
  2. kannst DU Konsolenprogramme auch statisch Linken, dann brauchst Du auch die DLL nicht.

#19

Die cygwin DLL kann AFAIK nicht statisch gelinkt werden (hatte ich auch nachgesehen, aber siehe https://www.cygwin.com/faq.html#faq.programming.static-linking ;-))