Forum: Compiler & IDEs avr-g++: external linkage von const/PROGMEM Symbol.


von E. H. (emax)


Angehängte Dateien:

Lesenswert?

UPDATE: Korrigierte main.cpp, aber gleiches Problem (das größere Archiv 
ist das richtige)
-------------------------------------------------

Ich scheitere aktuell an dem Versuch, ein Symbol/Objekt extern in ein 
avr-Programm zu linken.

Da das Gesamtprojekt zu komplex ist, habe ich ein kleines Beispiel mit 
genau diesem Problem gestrickt, es ist komplett im zip-Archiv vorhanden.

Hier das (korrigierte) Beispiel:
--------------------------

#pragma GCC optimize ("0")

#include "Bitmap.h"

#include <avr/pgmspace.h>
#include <avr/io.h>
#include <stdint.h>


extern Bitmap               bm;
extern const Bitmap         cbm;
extern const Bitmap PROGMEM cbmp;

int main(void)
{
  // irgendwie verwenden, ansonsten sinnlos
  PORTB = bm.xsize;      // ok
  PORTC = pgm_read_byte(&(cbm.xsize));     // undefined reference to 
`cbm'
  PORTD = pgm_read_byte(&(cbmp.xsize));    // undefined reference to 
`cbmp'
  while(1)
    ;
} // main

-----------------------

Zuerst habe ich erst mal alle Optimierungen ausgeschaltet, die haben 
mich schon öfter gefoppt.

Ansonsten simpler Code. Ich möchte eine Bitmap im Flash ablegen, und 
diese nicht in "main.cpp" halten, sondern in einer externen Quelle. Die 
Bitmap mit in main.cpp zupacken is keine Option: Im richtigen Leben 
handelt es sich dabei um ein paar Fonts, die selektiv zum finalen Binary 
gelinkt werden, was üblichweise ja auch funktioniert.

Zunächst dachte ich, dass meine Migration von C nach C++ mir da einen 
Streich spielt, weil das 'extern' da wohl eine etwas andere Semantik 
hat. Deshalb habe ich es mit beiden Sprachen versucht (siehe makc und 
makcpp im Archiv). Aber es bleibt sich gleich. Die Dateiendung 'cpp' 
heißt ja nichts, es wäre sinnlos, die exakt gleiche Source noch mal als 
'c' Datei beizufügen.

Das kommt dabei raus:
--------------------

$ avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL \
  -Wall -funsigned-char -save-temps -mcall-prologues \
  Bitmap.cpp main.cpp --output main.elf  -Wl,-Map=main.map,--cref

main.o: In function `main':
main.cpp:(.text+0x1e): undefined reference to `cbm'
main.cpp:(.text+0x2a): undefined reference to `cbmp'
collect2: error: ld returned 1 exit status

Compilation exited abnormally with code 1 at Wed Nov 20 14:13:51

----------------

Sobald ich die Bitmap 'const' oder gar const PROGMEM definiere, steigt 
der Linker aus. Raff ich nicht. Ich bilde mir ein, das schon etliche 
Male so gemacht zu haben, aber irgendwas übersehe ich wohl.

Bin dankbar für jeden Hinweis.


PS: Ich habs mit zwei Compiler Versionen versucht, der 7.3.0 und zuletzt 
der 4.9.2:

$ avr-gcc --version
avr-gcc (GCC) 4.9.2

$ avr-g++ --version
avr-g++ (GCC) 4.9.2

: Verschoben durch Admin
von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> extern Bitmap               bm;
> extern const Bitmap         cbm;
> extern const Bitmap PROGMEM cbmp;

Das sind nur Deklarationen. Wo sollen denn den die Definitionen sein. 
Die ODR muss schon beachtet werden.

von E. H. (emax)


Lesenswert?

> Wo sollen denn den die Definitionen sein.

In Bitmap.cpp. Steht mit im Compiler-Aufruf, s.o.

Siehe 'extern Bitmap bm;' Wird ja auch korrekt aufgelöst. Die 
Linker-Fehler kommen nur bei den 'const' Varianten.

von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> In Bitmap.cpp. Steht mit im Compiler-Aufruf, s.o.

Sorry, hatte das .zip nicht gesehen.

Bei C++ bedeutet const immer internal-linkage.
Du musst also bei der Definition extern const schreiben.

von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Zuerst habe ich erst mal alle Optimierungen ausgeschaltet, die haben
> mich schon öfter gefoppt.

Wenn das passiert, hast Du versteckt in Deinem Code UB drin, sprich, 
Dein fehlerhaftes Programm läuft mit -O0 scheinbar korrekt. Bei -O1, ... 
fällt dann das UB aber auf. Es ist also nicht der Fehler des Compilers, 
wie Du meinst, sondern Deiner.

von E. H. (emax)


Lesenswert?

Hammer!

Tausend Dank! Das löst zunächst mal mein Problem. :-)

Was ich nicht verstehe: Das Problem besteht auch in 'C', wenn ich also 
mit 'gcc' kompiliere. Dabei habe ich das "schon immer" (tm) so gemacht. 
Dachte ich jedenfalls.

Könnten aber auch elementare Typen gewesen sein, mit denen gehts auch 
ohne 'extern' bei der Definition.

Wie auch immer: Ich kann erst mal weiter machen. Wenn es in 'C' auch das 
Schlüsselwort 'extern' braucht, muss ich meine Erfahrungen wohl mal 
überdenken. Könnte aber sein, dass ich composite-Typen (structs, Klassen 
et. al.) in den letzten 20 Jahren tatsächlich nie als extern-Referenz 
eingesetzt habe. Das 'extern' Schlüsselwort war (und ist) in den 
Projekten, in denen ich mitgearbeitet habe immer verpönt 
(Server-Anwendungen, embedded mache ich nur privat zur Entspannung).

---

Zum Thema allgemein, was ich da überhaupt mache: Embedded Sachen mache 
ich eigentlich seit je her in 'C', zuweilen mit ein paar Schnipseln 
Assembler. Da fühle ich mich sicher - auch wenn mich das aktuelle 
Problem hier gerade doch etwas verunsichert hatte ;-).

Nun kommt man ja irgendwie nicht umhin, sich mal ein eigenes Bild von 
C++ auf µP zu machen. Ein paar Threads hier habe ich dazu gelesen, aber 
ich denke, ein eigenes, etwas größeres Projekt ist der ideale 
Prüfungsfall.

Aus diesem Grund bin ich dabei, eine gut laufende C-Bibliothek nach C++ 
zu migrieren. Zunächst erst mal kompilierbar zu machen (ohne 'extern 
"C"' Tricks), Fehler- und Warnungsfrei zu bekommen, und dann Stück für 
Stück die Goodies aus der C++ Welt zu verwenden. Damit meine ich 
Compile-Time Argumente für konstante Composite-Typen (i.e.: 
template-Parameter), namespaces - weil die wirklich was bringen, und 
sicher noch ein paar andere nützliche Dinge. Das Ziel ist, eine 
vernünftige, also noch lesbare Abstraktion hin zu bekommen, und so wenig 
wie möglich Parameter während der Laufzeit hin- und her zu schaufeln, 
denn vieles geht ja in C++ mit den genannten template-Parametern. Die 
mag ich zwar nicht, aber wenns der Lösungsfindung dient ...

Das ist jedenfalls der Hintergrund.

Nochmals danke für die flotte Hilfe!

von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Was ich nicht verstehe: Das Problem besteht auch in 'C',

Du kompilierts bestimmt als:

gcc abc.cc

oder

gcc abc.cpp

oder?
Dann aerbeitet der gcc im C++-Mode.

von E. H. (emax)


Lesenswert?

Ja stimmt, werd ich mal anders probieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Ja stimmt, werd ich mal anders probieren.

gcc -x c abc.cpp

schaltet unabhängig von irgendwelchen Heuristiken C-Language ein.

von E. H. (emax)


Lesenswert?

Eben probiert, stimmt.

Das ist wieder so ein schlauer Automatismus, wie sie mich dutzendweise 
nerven. Wenn ich 'gcc' aufrufe, möchte ich ein C-Programm kompilieren, 
egal welche Dateierweiterung das hat. Scheint wieder so eine 
Windows-Allüre zu sein (das ist diese komische Anwendung, die Programme 
am Namen '*.exe' erkennt).

Was für ein Schwachfug.

von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Wenn ich 'gcc' aufrufe, möchte ich ein C-Programm kompilieren,
> egal welche Dateierweiterung das hat. Scheint wieder so eine
> Windows-Allüre zu sein (das ist diese komische Anwendung, die Programme
> am Namen '*.exe' erkennt).

Nein.
Das liegt daran, dass gcc fälschlicherweise mit gnu-c-compiler 
assoziiert wird. Es bedeutet aber gnu-compiler-collection (c, c++, 
obj-c, ada, fortran, ...)

: Bearbeitet durch User
von E. H. (emax)


Lesenswert?

> Das liegt daran, dass gcc fälschlicherweise mit gnu-c-compiler
> assoziiert wird. Es bedeutet aber gnu-compiler-collection

Das weiß ich.

Dass nun aber gcc die Dateiendung zur Indentifikation seiner Aufgabe 
verwendet ist zumindest nicht das *ix-Paradigma, welches auf 
Dateinamens-Erweiterungen ja noch nie viel gegeben hat.

Dafür gab es seit je her '[/usr/share/file/]magic'.

Und vor allem: Wozu dann das 'g++' Kommando ? Damit kann ich doch 
explizit angeben, was ich möchte? Jedenfalls wäre Letzteres bei so viel 
Schlauheit - wenn diese denn funktionieren würde - überflüssig.

Mir ist das noch nie in die Quere gekommen, weil ich meine Dateien 
ansonsten nach gängigen Normen benenne. Was auch gut so ist, weils 
andernfalls in die Hose gehen kann, wie ich mit diesem Fall hier wohl 
zur Kenntnis nehmen muss: Es kann nämlich durchaus sein, dass ich 
deshalb Stunden verplempert habe, weil ich zu Testzwecken die 
'falschen' Dateinamen verwendet habe. Ja isses toll.

Nur meine 2 Cent.


Trotzdem wieder was gelernt. Wusste ich nicht, danke.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Und vor allem: Wozu dann das 'g++' Kommando ? Damit kann ich doch
> explizit angeben, was ich möchte? Jedenfalls wäre Letzteres bei so viel
> Schlauheit - wenn diese denn funktionieren würde - überflüssig.

Nicht ganz, weil der Aufruf desselben Executables als g++ bedeutet, dass 
auch die libstdc++ hinzugebunden wird, was bei gcc nicht passiert.

Beitrag #6046076 wurde von einem Moderator gelöscht.
von E. H. (emax)


Lesenswert?

Es lässt sich sicher ein Begründung finden.

Dennoch finde ich solche Programm-Eigenmächtigkeiten ohne explizite 
Anweisung  wenig sinnvoll, ich sehe den Mehrwert nicht. Im Gegenteil, 
das kann auch nett in die Hose gehen.

Mich grauts vor Programmen, die "annehmen", sie wüssten, was der Nutzer 
will. Der einzige, der das wirklich weiß, bin (in meinem Fall) ich.

Fatal vor allem, wenn man so wie ich doch tatsächlich noch dran glaubt, 
dass Kommandos (i.e. Programmaufrufe) unter Linux nur genau das tun, was 
man per Aufruf auch festlegt.

Dazu gehört m.E. nicht, dass Anwendungen nun anfangen, besonders schlau 
zu sein. Ich wüsste nämlich z.B. nicht, dass irgendwo festgelegt wäre, 
mit welchen Buchstaben der Name einer Quelldateai von Tyxp 'C/C++' 
et.al. aufzuhören hätte. Da ist die "Annahme", es müsse sich bei 
bestimmten Endungen um bestimmte Programmtypen handeln durchaus kühn. 
Schon (und vor allem) die Unterscheidung 'c' und 'C' ist da kritisch, 
denn nicht alle Systeme können das überhaupt unterscheiden (div. Windows 
Versionen, OS400, 3270-Umgebung u.a.). Genau das macht der gcc aber, wie 
ich nach Deinem Hinweis vorhin mit Erstaunen nachlesen konnte.

Aber auch solcher Unfug (Gross-Kleinschreibung zu ignorieren) ist ja 
neuerdings auf dem Weg ins Linux-Land. Spätestens dann wirds mit der 
"intelligenten" Unterscheidung von '*.c' und '*.C' schwierig werden.

Da lach ich dann schon mal im Voraus. :-)

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

E. H. schrieb:
> Mich grauts vor Programmen, die "annehmen", sie wüssten, was der Nutzer
> will.

Dann halte dich von Apple Produkten fern.

von E. H. (emax)


Lesenswert?

Das mache ich. Konsequent. Schon lange.

von mh (Gast)


Lesenswert?

E. H. schrieb:
> Dazu gehört m.E. nicht, dass Anwendungen nun anfangen, besonders schlau
> zu sein. Ich wüsste nämlich z.B. nicht, dass irgendwo festgelegt wäre,
> mit welchen Buchstaben der Name einer Quelldateai von Tyxp 'C/C++'
> et.al. aufzuhören hätte. Da ist die "Annahme", es müsse sich bei
> bestimmten Endungen um bestimmte Programmtypen handeln durchaus kühn.

Wieso hast du dann den Compiler mit Dateien gefüttert, ohne ihm zu sagen 
was genau das für Dateien sind? Bist du etwa davon ausgegangen, dass er 
magisch weiß was er damit machen soll?

von Oliver S. (oliverso)


Lesenswert?

E. H. schrieb:
> Dennoch finde ich solche Programm-Eigenmächtigkeiten ohne explizite
> Anweisung  wenig sinnvoll

Na ja, der gcc macht das seit Anbeginn der Zeitrechnung so, und das ganz 
unabhängig vom Betriebssystem, auf dem er läuft.

Und ganz ohne RTFM ist die Nutzung solcher Tools halt Glückssache.

Oliver

von E. H. (emax)


Lesenswert?

> Bist du etwa davon ausgegangen, dass er
> magisch weiß was er damit machen soll?

Ich bin davon ausgegangen, dass 'gcc' eine C-Quelle erwartet, und 'g++' 
eine C++ Quelle. So wie ich z.B. auch davon ausgehe, das 'rm' die 
Datei/en, die angebe, löscht.

Bei 'gcc' habe ich mich getäuscht.

von mh (Gast)


Lesenswert?

Oliver S. schrieb:
> E. H. schrieb:
>> Dennoch finde ich solche Programm-Eigenmächtigkeiten ohne explizite
>> Anweisung  wenig sinnvoll
>
> Na ja, der gcc macht das seit Anbeginn der Zeitrechnung so, und das ganz
> unabhängig vom Betriebssystem, auf dem er läuft.
>
> Und ganz ohne RTFM ist die Nutzung solcher Tools halt Glückssache.
>
> Oliver

Man muss nicht sehr lange in dem FM lesen. Die ersten zwei Zeilen der 
gcc-man-page:
1
NAME
2
       gcc - GNU project C and C++ compiler

von E. H. (emax)


Angehängte Dateien:

Lesenswert?

> Und ganz ohne RTFM ist die Nutzung solcher Tools halt Glückssache.

Dem stimme ich durchaus zu. Allerdings hat es auch etwas mit Gewöhnung 
zu tun, und sicher z.T. auch mit Annahmen, die dann man revidieren muss. 
Das stelle ich gar nicht in Abrede.

Im Übrigen bezweifle ich stark, dass sich so leicht jemand finden lässt, 
der alleine die 'man' Pages  von gcc wirklich durchgelesen hat. Sie 
finden sich im angehängten PDF: 358 Seiten. Da kann einem so was wie 
Namenssensitivität schon mal entgehen, insbesondere wenn man viele Jahre 
lang mit deren Auswirkungen nicht in Berührung gekommen ist.

Das geht aber alles völlig an der Frage vorbei, ob Dateierweiterungen 
ein haltbares Kriterium für deren Inhalt sind.

Ich finde nicht. Aber das ist nur meine Meinung.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

E. H. schrieb:
> Ich finde nicht. Aber das ist nur meine Meinung.

Das ist das schöne an Meinungen: Jeder kann problemlos beliebig viele 
davon haben.

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Dafür gab es seit je her '[/usr/share/file/]magic'.

Sicher.
Aber wie Du sicher weißt, funktioniert das zu 100% nur bei Binärdateien, 
die mit einer Magic-Number beginnen. Bei Text-Files ist auch libmagic 
auf eine Heuristik angewiesen. Und die geht genauso oft schief, Du 
darfst das gerne mit dem Kommando file an Deinen C++-Quellen einmal 
ausprobieren. Die werden nämlich von file als C-Source erkannt.
Nun haben wir also zwei Heuristiken: einmal libmagic und einmal den 
Namenssuffix. Der gcc benutzt die zweite Heuristik, die für solche 
ähnlichen bzw. identischen Dateiinhalte wie C vs C++ die bessere ist.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> E. H. schrieb:
>> Dennoch finde ich solche Programm-Eigenmächtigkeiten ohne explizite
>> Anweisung  wenig sinnvoll
>
> Na ja, der gcc macht das seit Anbeginn der Zeitrechnung so, und das ganz
> unabhängig vom Betriebssystem, auf dem er läuft.

Was einfach daran liegt, dass der Compiler-Treiber (um den handelt es 
sich bei "gcc", oder auch beim klassischen "cc") schon immer 
verschiedene Arten von Eingabedateien akzeptieren konnte: 
Assemblerquelldateien mit und ohne Preprocessing, C-Dateien, 
Objektmodule, Objekt-Bibliotheken. Die wurden seit jeher anhand der 
Dateinamensendung unterschieden. Also sowas wie:
1
cc startup.S mycode.c topsecretobject.o foreignlibrary.a -o foobar -lm

In Abhängigkeit dessen, was er zu verarbeiten hat, wirft er die 
einzelnen Backends an: Präprozessor (inzwischen implizit im Compiler, 
früher ein separates Binary), Compiler, Assembler, Linker.

: Bearbeitet durch Moderator
von E. H. (emax)


Lesenswert?

> In Abhängigkeit dessen, was er zu verarbeiten hat, wirft er die
> einzelnen Backends an: Präprozessor (inzwischen implizit im Compiler,
> früher ein separates Binary), Compiler, Assembler, Linker.

Das hat sich, wie ich vorhin beim Quer-Lesen der man-Pages feststellen 
musste, enorm entwickelt.

In meiner DLD Zeit (Deutsche Linux Distribution, Kernel 0.99xyz, um 
1990, drei oder vier Dutzend Disketten),  machte ich die ersten Schritte 
mit gcc. Damals war das "der C-Compiler" unter Linux. Irgendwann wurde 
ich dann zwar schon gewahr, dass gcc tatsächlich die Gnu Compiler 
Collection ist, aber in meiner Praxis hatte ich immer 'gcc' für die 
Kompilierung von *.c Sources verwandt, und später 'g++' für die 
Kompilierung von '*cpp' oder '*cxx' Sources.

So blieb das über die Jahre, alles andere war eher ausgeblendet (ich 
brauchte es nicht).

So lernt man dann halt durch Erfahrung hinzu. So wie ich in diesem Fall 
jetzt, in dem es dann tatsächlich mal relevant wurde.


Man lernt auch noch kurz vor der Rente - was ja nicht schlecht ist.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

E. H. schrieb:
> Das ist wieder so ein schlauer Automatismus, wie sie mich dutzendweise
> nerven. Wenn ich 'gcc' aufrufe, möchte ich ein C-Programm kompilieren,

Du willst also, dass beim Aufruf

gcc modul1.o modul2.o main.o -o main.elf

modul1.o, modul2.o und main.o also C-Dateien interpretiert werden?

Kein Problem:  Verwende anstatt gcc — was ja nur ein Compiler-Treiber 
ist, einfach

cc1 modul1.o modul2.o main.o -o main.elf

Also:

C-Code    = cc1
C++-Code  = cc1plus
Assembler = as
Objects   = ld
LTO-Code  = lto1

> Was für ein Schwachfug.

Nur die falschen Tools verwendet!

Nimm cc1 und du wirst glücklich.

Und nach 5 Minuten noch glücklicher, dass es gcc und g++ gibt ;o)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

E. H. schrieb:
> und später 'g++' für die Kompilierung von '*cpp' oder '*cxx' Sources.

Das ist auch völlig korrekt. Es ändert nämlich insbesondere die 
Argumente beim Linken. Setz' ein "-v" zur Kommandozeile hinzu, und der 
Compiler-Treiber erzählt dir, was er im Hintergrund alles wie werkeln 
lässt.

von Rolf M. (rmagnus)


Lesenswert?

E. H. schrieb:
> Mir ist das noch nie in die Quere gekommen, weil ich meine Dateien
> ansonsten nach gängigen Normen benenne. Was auch gut so ist, weils
> andernfalls in die Hose gehen kann, wie ich mit diesem Fall hier wohl
> zur Kenntnis nehmen muss:

Hast du echt gedacht, dass erstmal das ganze File analysiert wird, um am 
Inhalt zu erkennen, ob das jetzt C oder C++ sein soll, bevor der 
eigentliche Compiliervorgang startet? Das wäre nicht nur langsam, 
sondern auch unzuverlässig. Es kann ja durchaus auch sein, dass man es 
am File selbst gar nicht erkennt, sondern nur an irgendeinem der 
eingebundenen Header. Oder daran, womit es später mal zusammengelinkt 
wird. Das kann also im Gegensatz zu einer Namensendung nicht sauber 
funktionieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Hast du echt gedacht, dass erstmal das ganze File analysiert wird, um am
> Inhalt zu erkennen, ob das jetzt C oder C++ sein soll, bevor der
> eigentliche Compiliervorgang startet?

Das habe ich oben schon geschrieben.

ich glaube, er hat einfach nicht bedacht, dass seine Forderung nicht 
erfüllbar ist. Denn C und C++ kann identischer Code sein. Er wünscht 
sich also ein Compiler-Frontend, dass eine Entscheidung trifft, die 
unmöglich ist. Bzw. die nur von außen vorgebbar ist. Zudem wusste er 
selbst nicht genau, wie übersetzt werden soll ... da wird es dann 
schwierig für das Frontend.

von E. H. (emax)


Lesenswert?

Hallo Johann,

> Du willst also, dass beim Aufruf
> gcc modul1.o modul2.o main.o -o main.elf
> modul1.o, modul2.o und main.o also C-Dateien interpretiert werden?

ich nehme an, dass die '*o' als Binärdateien erkannt und an ld weiter 
gereicht werden. Da wäre gcc dann nur eine Durchreiche.

Da ich aber Deinen Hintergrund kenne, verbietet mir mein Respekt echten 
Widerspruch.

Ich hab ja oben geschrieben, dass ich immer noch dazu lerne bzw. es 
zumindest versuche.

Allerdings frage ich mich immer noch, ob die Endungen von Dateinamen bei 
der Einführung case-insensitiver Dateisysteme noch als Erkennungsmerkmal 
haltbar sein werden.

Es sein denn, die betroffenen Tools werden für solche Konfigurationen 
einfach nicht freigegeben. Was ich verstehen würde.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

E. H. schrieb:
> Allerdings frage ich mich immer noch, ob die Endungen von Dateinamen bei
> der Einführung case-insensitiver Dateisysteme noch als Erkennungsmerkmal
> haltbar sein werden.

Wer will denn so einen Murks!

Ich denke, gcc geht von einem Posix-konformen OS aus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

E. H. schrieb:
> Allerdings frage ich mich immer noch, ob die Endungen von Dateinamen bei
> der Einführung case-insensitiver Dateisysteme noch als Erkennungsmerkmal
> haltbar sein werden.

Welche "case-insensitiven Dateisysteme" meinst du? CP/M, RSX-11? FatFS 
oder NTFS sind nicht per se "case insensitive", sie sind als Dateisystem 
"case preserving". Nur die Windows-Systemaufrufe darüber sind case 
insensitive.

Daher ist es unter Windows auch nicht möglich, "foobar.S" in "foobar.s" 
umzubenennen, denn aus Sicht der Windows-Systemaufrufe sind beides die 
gleiche Datei, obwohl sie dir durchaus mit der im Dateisystem 
gespeicherten Groß-/Kleinschreibung angezeigt werden.

Aber das Dateisystem entscheidet hier sowieso nichts. Entscheidend ist 
lediglich, ob du dem Compiler-Treiber gegenüber auf der Kommandozeile 
die Datei dann "foobar.s" oder "foobar.S" nennst: im zweiten Falle würde 
er vor dem Asssemblerlauf noch den Präprozessor drüber schicken. Unter 
Windows würde er in beiden Fällen dann sowohl "foobar.s" als auch 
"foobar.S" als akzeptable Quelldatei finden.

von Rolf M. (rmagnus)


Lesenswert?

E. H. schrieb:
> Hallo Johann,
>
>> Du willst also, dass beim Aufruf
>> gcc modul1.o modul2.o main.o -o main.elf
>> modul1.o, modul2.o und main.o also C-Dateien interpretiert werden?
>
> ich nehme an, dass die '*o' als Binärdateien erkannt und an ld weiter
> gereicht werden. Da wäre gcc dann nur eine Durchreiche.

Im Prinzip ja.

> Allerdings frage ich mich immer noch, ob die Endungen von Dateinamen bei
> der Einführung case-insensitiver Dateisysteme noch als Erkennungsmerkmal
> haltbar sein werden.

Je nach Endung. Ein Problem wäre dort, dass .c für C-Dateien steht, .C 
aber für C++, oder dass .s für Assembler-Code ohne und .S für welchen 
mit Präprozessorlauf steht. Und es gibt noch andere Inkompatibilitäten 
mit bestimmten Dateisystemen, wie z.B. dass .c++ bei manchen nicht geht, 
weil kein + in Dateinamen erlaubt ist. Man kann's halt nicht allen recht 
machen.
Und natürlich werden ggf Dinge wie .cPp nicht erkannt, weil es entweder 
.cpp oder .CPP sein muss.

Jörg W. schrieb:
> Nur die Windows-Systemaufrufe darüber sind case insensitive.

Kann man anscheinend bei Windows 10 umschalten - lustigerweise sogar pro 
Verzeichnis.
https://www.howtogeek.com/354220/how-to-enable-case-sensitive-folders-on-windows-10/

Offenbar wurde das für WSL eingeführt.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Jörg W. schrieb:
> Was einfach daran liegt, dass der Compiler-Treiber (um den handelt es
> sich bei "gcc", oder auch beim klassischen "cc") schon immer
> verschiedene Arten von Eingabedateien akzeptieren konnte:

Oder anders gesagt, das ist ein Grundprinzip vom gcc (und von vielen 
anderen Compilern). Sich darüber aufzuregen ist einfach 
Realitätsverweigerung.

Oliver

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

E. H. schrieb:
>> Du willst also, dass beim Aufruf
>> gcc modul1.o modul2.o main.o -o main.elf
>> modul1.o, modul2.o und main.o also C-Dateien interpretiert werden?
>
> ich nehme an, dass die '*o' als Binärdateien erkannt und an ld weiter
> gereicht werden.

*.o sind hier keine Binärdateien, sondern (ELF) Object-Dateien.  Als 
Binärdatei würde ich bezeichnen, was ohne jegliche Transformation 
verwendet wird, zum Beispiel per .incbin im Assembly.

> Da wäre gcc dann nur eine Durchreiche.
>
> Ich hab ja oben geschrieben, dass ich immer noch dazu lerne bzw. es
> zumindest versuche.

Und es lernt sich besser, wenn man Sinn und Zweck kennt.  Wie Jörg oben 
schieb:  Gib einfach mal allen gcc/g++ Ausrufen zusätzlich -v oder noch 
besser -v -Wl,-v mit.  Da ist schon einiges was gcc da an Optionen 
zusammenstöpselt.  Das will man nicht händisch machen.

Ein häufiger Fehler beim Linken ist zum Beispiel, dass ld direkt 
aufgerufen wird aber nicht mit den richtigen Optionen, etwa für 
Multilib-Auswahl oder Plugin-Aufrufe wie bei LTO (-flto).

> Allerdings frage ich mich immer noch, ob die Endungen von Dateinamen bei
> der Einführung case-insensitiver Dateisysteme noch als Erkennungsmerkmal
> haltbar sein werden.

Bei .c / .C und .S / .s hat man dann eine blöde Kombination von Endung 
und OS oder Filesystem.  Also einfach von Anfang an allen Problemen aus 
dem Weg gehen indem man das vermeidet und C++ .cpp nennt.  Und 
Assembly-Quellen als .sx.

Ist mir 1× unter Windos passiert, dass ich im Makefile eine clean Rule 
hatte mit rm -f *.s um Überbleibsel von -save-temps aufzuräumen.  Und 
*.S Assembly-Quellen.  Seither verwende ich *.sx für Assembly.

von E. H. (emax)


Lesenswert?

Wilhelm M. schrieb:

> Wer will denn so einen Murks!

Tja, das dachte ich auch immer.

Linux, Kernel 5.2:

"Das Ext4-Dateisystem kann jetzt Groß- und Kleinschreibung ignorieren."

Siehe 
https://www.heise.de/ct/artikel/Linux-5-4-freigegeben-exFAT-Support-und-Einschraenkungen-fuer-Root-4541639.html?seite=all.

Der Wahnsinn grassiert.

Dann werden Dateiendungen *.c vs. *.C für gcc auch unter Linux kein 
verlässliches Attribut mehr sein.

von E. H. (emax)


Lesenswert?

Rolf M. schrieb:

> Hast du echt gedacht, dass erstmal das ganze File analysiert wird, um am
> Inhalt zu erkennen, ob das jetzt C oder C++ sein soll, bevor der
> eigentliche Compiliervorgang startet?

Wie Du meinen Antworten entnehmen könntest, bin ich davon ausgegangen, 
dass 'gcc' und 'g++' zwei unterschiedliche Dateitypen erwarten. Das war 
ja nun keine vollkommen abwegige Annahme.

Aber das ist nun geklärt. Ich lerne, wie ich ja schon geschrieben habe, 
immer noch dazu.

: Bearbeitet durch User
von E. H. (emax)


Lesenswert?

Kleine Korrektur: Ich meinte natürlich Kernel 5.4, und der Heise-Link 
oben ist auch falsch.

Ich meinte diesen hier (falsches Copy & Paste):

https://www.heise.de/ct/artikel/Linux-5-2-freigegeben-Aenderungsrekord-und-Geschwindigkeitsverbesserungen-4424484.html

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

E. H. schrieb:
> Dann werden Dateiendungen *.c vs. *.C für gcc auch unter Linux kein
> verlässliches Attribut mehr sein.

Auch du hast noch nicht begriffen, dass das gar nicht vom Dateisystem 
abhängt, sondern ausschließlich davon, was du dem Compiler auf der 
Kommandozeile sagst. Nennst du die Datei auf der Kommandozeile foo.c, 
wird sie als C-Sourcecode betrachtet, nennst du sie foo.C, wird sie als 
C++ angesehen. Inwiefern das Dateisystem für beide Namen die gleiche 
Datei finden würde oder nicht, interessiert den Compiler gar nicht.

Es wurde oben schon geschrieben, wirklich „interessante“ Effekte hat man 
dabei eher an unerwarteten Stellen: eine "clean"-Regel eingerichtet, die 
*.s löscht (weil dies ja sonst nur als Assembler-Zwischencode anfällt), 
und man hat echte Assemblerquellen wie foo.S dabei, dann räumt einem 
"make clean" die Assemblerquellen mit ab, wenn das Dateisystem die Namen 
nicht unterscheiden kann. :-o

von E. H. (emax)


Lesenswert?

Jörg W. schrieb:

> Auch du hast noch nicht begriffen, dass das gar nicht vom Dateisystem
> abhängt, sondern ausschließlich davon, was du dem Compiler auf der
> Kommandozeile sagst.

Ob der Compiler per default die Endung als Attribut zur Identifikation
des Dateiinihaltes nimmt oder nicht, hängt ausschließlich vom Compiler 
ab.

Was der Compiler als Kommando bekommt, ist dabei spätestens bei der 
Verwendung generischer Makefiles (oder scons-builds oder, oder) in 
größeren Projekten mit Dutzenden oder hunderten von Dateien keine 
Einzelentscheidung mehr, sondern eben eine generische. Im Gegensatz 
dazu kann natürlich jeder, der Spaß dran hat, das natürlich für jede 
Einzeldatei individuell angeben. Viel Spaß dabei, besonders, wenn man 
nicht der Einzige ist, der in so ein Repository mit vielleicht hunderten 
Dateien schreibt.

Dass bei den erwähnten Dateien die Unterscheidung des vermuteten Inhalts 
nach  Groß-/Kleinschreibung dann noch einen Sinn hat, bezweifle ich sehr 
stark.

Im Übrigen verstehe ich solch trotzige Entgegnungen nicht, wo ich doch 
längst "zugegeben" habe, dass ich von falschen Annahmen ausgegangen bin.

Deshalb ist für mich dazu eigentlich alles gesagt. Wenn auch noch nicht 
von Jedem.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

E. H. schrieb:
> Was der Compiler als Kommando bekommt, ist dabei spätestens bei der
> Verwendung generischer Makefiles (oder scons-builds oder, oder) in
> größeren Projekten mit Dutzenden oder hunderten von Dateien keine
> Einzelentscheidung mehr, sondern eben eine generische.

Da alle derzeit existierenden Dateisysteme case-preserving sind (auf 
CP/M oder RSX-11 arbeitet aktuell ganz sicher niemand mehr), musst du in 
diesem Falle einzig und allein beim Anlegen der Datei die richtige 
Endung vergeben. Das musst du aber letztlich sowieso, egal ob du die 
Datei nun .cxx oder .C nennst.

ps: Generisches "make" kennt sowieso keine Wildcards als 
Quelldateinamen. Bei GNU make glaube ich mich zu erinnern, dass sie das 
pattern matching selbst machen, insofern findet dort ein "*.c" sehr 
wahrscheinlich kein "foo.C", sondern nur ein "foo.c" – auch unter 
Windows. Könnte ja mal jemand ausprobieren, wenn's ihn interessiert.

: Bearbeitet durch Moderator
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

E. H. schrieb:
> Was der Compiler als Kommando bekommt,

Was meinst du eigentlich mit "Compiler?"

gcc ist jedenfalls kein Compiler, und g++ auch nicht.  Das sind wie 
gesagt Treiberprogramme, die selbst keine Compilierung ausführen — und 
auch keine Assemblierung, Linking oder Preprocessing.

Der C-Compiler der GNU-Tools ist cc1; der C++-Compiler ist cc1plus.

von neuer PIC Freund (Gast)


Lesenswert?

Und wenn man die "extern x Bitmap y z;" Deklarationen nach Bitmap.h 
verschiebt, validiert die Fragestellung gegen Null. Dann läuft auch der 
gcc, egal ob mit "-x c" oder "-x c++", durch.

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> E. H. schrieb:
>> Was der Compiler als Kommando bekommt,
>
> Was meinst du eigentlich mit "Compiler?"
>
> gcc ist jedenfalls kein Compiler, und g++ auch nicht.

Sie sind das Compiler-Frontend, was man im Bezug auf den Aufruf durch 
den Benutzer daher als "Compiler" sehen kann. So sieht es übrigens, wie 
schon erwähnt wurde, auch die man-Page.

> Das sind wie gesagt Treiberprogramme, die selbst keine Compilierung
> ausführen — und auch keine Assemblierung, Linking oder Preprocessing.

"Treiberprogramme"?

> Der C-Compiler der GNU-Tools ist cc1; der C++-Compiler ist cc1plus.

Die ruft aber keiner direkt auf, und sie sind auch nicht dafür gedacht.

von neuer PIC Freund (Gast)


Lesenswert?

> Die ruft aber keiner direkt auf, und sie sind auch nicht dafür gedacht.

Ich weiss nicht mehr welche IDE es war. Aber diese rief mit ihrem 
internen make cc1 direkt auf. Ohne gcc - Frontend.

von Wilhelm M. (wimalopaan)


Lesenswert?

neuer PIC Freund schrieb im Beitrag #6058206:
> validiert die Fragestellung gegen Null

Den Satz würde ich nochmal überdenken:

https://www.duden.de/rechtschreibung/validieren

von Eric B. (beric)


Lesenswert?

Jörg W. schrieb:
> Es wurde oben schon geschrieben, wirklich „interessante“ Effekte hat man
> dabei eher an unerwarteten Stellen: eine "clean"-Regel eingerichtet, die
> *.s löscht (weil dies ja sonst nur als Assembler-Zwischencode anfällt),
> und man hat echte Assemblerquellen wie foo.S dabei, dann räumt einem
> "make clean" die Assemblerquellen mit ab, wenn das Dateisystem die Namen
> nicht unterscheiden kann. :-o

weswegen man immer ein Build-Verzeichnis benutzen soll, anstatt die 
Quelldatei-Verzeichnisse mit temporäre Dateien vollzumüllen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.