qualified-id in declaration before '(' token



  • Vielen Dank für deine geduldige Erklärung!!

    Ich habe die Funktion soweit angepasst:

    static void ChangeConfig(const sting keyvalue, const sting value)
    {
        ProfileMap configuration;
        Profile::Clear();
        Profile::ChangeConfig(configuration, "/boot/config.uEnv");
        configuration.Set(keyvalue, value);
        Profile::SaveFile(configuration, "/boot/config.uEnv");
    }
    

    Der Aufruf erfolgt mit:

    ChangeConfig("rotation", 1);
    

    Der Teil müsste so nun funktionieren, oder?

    Tatsächlich wird es auch einen Aufruf in der Art geben müssen:

    ChangeConfig("LANG", "de_DE.UTF-8");
    

    Das heißt, wenn ich dich richtig verstehe, dass das so noch nicht geht?



  • Kompilieren bringt noch Fehler:

    | src/OV/OpenVarioMenu.cpp:98:16: error: aggregate 'ProfileMap configuration' has incomplete type and cannot be defined
    |    98 |     ProfileMap configuration;
    |       |                ^~~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:99:14: error: 'Clear' is not a member of 'Profile'
    |    99 |     Profile::Clear();
    |       |              ^~~~~
    | src/OV/OpenVarioMenu.cpp:100:14: error: 'ChangeConfig' is not a member of 'Profile'; did you mean 'ChangeConfig'?
    |   100 |     Profile::ChangeConfig(configuration, "/boot/config.uEnv");
    |       |              ^~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:96:13: note: 'ChangeConfig' declared here
    |    96 | static void ChangeConfig(const string keyvalue, const string value)
    |       |             ^~~~~~~~~~~~
    | make: *** [build/compile.mk:107: output/UNIX/opt/src/OV/OpenVarioMenu.o] Error 1
    


  • Sorry, aber so wird das nichts - du mußt schon die Grundlagen (Syntax und Semantik) von C++ verstehen.

    Am besten (wenn du englisch kannst) mittels LearnCpp.
    Es gibt auch noch (für den Einstieg) Wiki: C++ Programmierung.
    Sonst s.a. noch Linkliste.

    Ich gebe dir jetzt (einmalig) mal den Code:

    #include "Map.hpp" // für ProfileMap
    
    static void ChangeConfig(const string &keyvalue, int value)
    {
        const char * const ConfigPath = "/boot/config.uEnv"; // um nur eine Codestelle dafür zu haben
    
        ProfileMap configuration;
        // Profile::Clear(); // <- diese Funktion gibt es wohl nicht bei XCSoar
        Profile::LoadFile(configuration, ConfigPath); // Funktionsname wieder zurück geändert
        configuration.Set(keyvalue, value);
        Profile::SaveFile(configuration, ConfigPath);
    }
    

    Für andere Aufrufe (z.B. string) bräuchtest du, wie schon geschrieben, ein Template:

    template<typename T>
    static void ChangeConfig(const string &keyvalue, T value)
    {
      // der Rest bleibt gleich
    }
    


  • Danke!! Ich schaue mir deine Empfehlungen an. So ganz allmählich blicke ich es aber schon. Allerdings führt deine Code noch zu Fehlern:

    | src/OV/OpenVarioMenu.cpp: In function 'void ChangeConfigInt(const string&, int)':
    | src/OV/OpenVarioMenu.cpp:102:38: error: could not convert 'ConfigPath' from 'const char* const' to 'Path'
    |   102 |     Profile::LoadFile(configuration, ConfigPath);
    |       |                                      ^~~~~~~~~~
    |       |                                      |
    |       |                                      const char* const
    | src/OV/OpenVarioMenu.cpp:103:22: error: no matching function for call to 'ProfileMap::Set(const string&, int&)'
    |   103 |     configuration.Set(keyvalue, value);
    |       |     ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
    | In file included from src/OV/OpenVarioMenu.cpp:42:
    


  • Ich habe mir die genaue API nicht angeschaut, sondern mich nur an deinem Code (+ den Fehlermeldungen) orientiert.
    Du mußt anscheinend ein Objekt der Klasse Path erzeugen und übergeben:

    const Path ConfigPath("/boot/config.uEnv"); // evtl. für Unicode: L"/boot/config.uEnv"
    

    Und statt string muß wohl direkt const char * als Typ für keyvalue verwendet werden (oder aber du benutzt beim Aufruf configuration.Set(keyvalue.c_str(), value).



  • Es läuft noch nicht ganz. Ich habe heute viel gelesen, um das Problem möglichst selbst zu finden, und denke, ich bin grundsätzlich auf der richtigen Spur. Folgender Fehler kommt noch:

    |   LINK    output/UNIX/bin/OpenVarioMenu
    | src/OV/OpenVarioMenu.cpp:176: error: undefined reference to 'Profile::LoadFile(ProfileMap&, Path)'
    | src/OV/OpenVarioMenu.cpp:177: error: undefined reference to 'ProfileMap::Set(char const*, int)'
    | src/OV/OpenVarioMenu.cpp:178: error: undefined reference to 'Profile::SaveFile(ProfileMap const&, Path)'
    | collect2: error: ld returned 1 exit status
    
    

    Das Problem ist wohl, das Profile nicht public ist. Soweit ich das recherchieren konnte, muss die Funktion ChangeConfigInt in Zeile 171 und folgende eingebunden werden. Damit sollte sie eigentlich public sein. Ich nehme aber an, dass da noch eine Kleinigkeit fehlt.

    Hier noch mal der Link zum Skript, damit es besser nachvollziehbar ist: https://github.com/freevariode/XCSoar/blob/master/src/OV/OpenVarioMenu.cpp



  • Mit public/protected/private hat das nichts zu tun.
    Das Problem ist dass die drei Funktionen einfach nirgends definiert sind.



  • Siehst du beim Kompilieren eine Liste der Dateien?
    Dabei sollten dann sowohl src/Profile/File.cpp als auch src/Profile/Map.cpp auftauchen (eigenartigerweise ist dort aber nur ProfileMap::Set(const char *key, const char *value) definiert und nicht die anderen Set-Überladungen, auch nicht in der Headerdatei ProfileMap.hpp).

    Nach Suche habe ich aber dann herausgefunden, daß die ProfileMap-Funktionen über diverse andere Source-Dateien (u.a. NumericValue.cpp) verteilt sind (very strange).
    Es sollten also alle Source-Dateien im Profile-Ordner mitkompiliert werden, so daß es keine Linkerfehler mehr gibt.



  • also in der Liste der Dateien beim Kompilieren kommen unter Anderem diese Dateien vor:

    |   CXX     output/UNIX/opt/src/Profile/Profile.o
    |   CXX     output/UNIX/opt/src/Profile/File.o
    |   CXX     output/UNIX/opt/src/Profile/Map.o
    

    wie in dieser Datei (https://github.com/XCSoar/XCSoar/blob/master/src/Input/InputEventsSettings.cpp) habe ich auch versuchsweise folgendes eingetragen:

    #include "Profile/Profile.hpp"
    #include "Profile/ProfileKeys.hpp"
    #include "Profile/Settings.hpp"
    #include "Profile/Current.hpp"
    

    Aber das verändert nichts. Ich verstehe nicht, was in dieser Datei anders gemacht wird als in meiner.



  • Ganz zum Schluß sollte es einen (wahrscheinlich sehr langen) Linkeraufruf geben, in welcher dann alle Objektfiles (.o) übergeben werden müssen - tauchen dort dann u.a. File.o, Map.o und auch NumericValue.o auf?

    Du solltest zumindestens den Compile- und Linkprozess verstehen, s. z.B. (in englisch) Introduction to the compiler, linker and libraries.



  • Du meinst diesen Bereich?

    |   LINK    output/UNIX/bin/xcsoar
    | rm output/data/icons/winpilot_reachable_160_alpha.png 
    output/data/icons/map_teammate_rgb.png 
    output/data/icons/map_taskturnpoint_alpha.png 
    output/data/icons/winpilot_marginal_160_rgb.png 
    output/data/icons/gps_lowsignal_160_rgb.png 
    output/data/icons/map_intersection_160_rgb.png 
    output/data/icons/map_ndb_160_rgb.png 
    output/data/icons/wrench_160_rgb.png 
    output/data/icons/map_tunnel_160_rgb.png 
    output/data/icons/map_target_rgb.png 
    output/data/icons/alt_marginal_airport_160_rgb.png 
    output/data/icons/map_small_160_alpha.png 
    output/data/icons/map_pgtakeoff_alpha.png 
    output/data/icons/map_reporting_point_160_alpha.png 
    output/data/icons/map_turnpoint_alpha.png 
    output/data/icons/gps_disconnected_rgb.png 
    output/data/icons/map_mountain_top_rgb.png 
    output/data/icons/map_intersection_160_alpha.png 
    output/data/icons/gps_lowsignal_rgb.png 
    output/data/icons/map_thermal_source_160_alpha.png 
    output/data/icons/alt_marginal_field_160_rgb.png 
    output/data/icons/flarm_alarm_alpha.png 
    output/data/icons/map_town_alpha.png output/data/
    ...
    gaaaaaaaaanz viele Zeilen
    ...
    
    | NOTE: make -j 4 HOSTCC=ccache gcc  HOSTCXX=ccache g++  AR=arm-
    ovlinux-linux-gnueabi-gcc-ar RANLIB=arm-ovlinux-linux-gnueabi-gcc-ranlib 
    CXX=ccache arm-ovlinux-linux-gnueabi-g++  -mthumb -mfpu=neon -mfloat-
    abi=hard -mcpu=cortex-a7 -fstack-protector-strong  -O2 -D_FORTIFY_SOURCE=2 
    -Wformat -Wformat-security -Werror=format-security --
    sysroot=/workdir/tmp/work/cortexa7t2hf-neon-ovlinux-linux-gnueabi/xcsoar-
    testing/git-r13/recipe-sysroot CC=ccache arm-ovlinux-linux-gnueabi-gcc  -
    mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 -fstack-protector-strong  
    -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-
    security --sysroot=/workdir/tmp/work/cortexa7t2hf-neon-ovlinux-linux-
    gnueabi/xcsoar-testing/git-r13/recipe-sysroot AS=arm-ovlinux-linux-gnueabi-as  
    LD=arm-ovlinux-linux-gnueabi-ld --sysroot=/workdir/tmp/work/cortexa7t2hf-
    neon-ovlinux-linux-gnueabi/xcsoar-testing/git-r13/recipe-sysroot  STRIP=arm-
    ovlinux-linux-gnueabi-strip CCACHE= DEBUG=n DEBUG_GLIBCXX=n 
    ENABLE_MESA_KMS=y GLES2=y GEOTIFF=n output/UNIX/bin/OpenVarioMenu
    |   CXX     output/UNIX/opt/src/Dialogs/ProcessDialog.o
    |   CXX     output/UNIX/opt/test/src/Fonts.o
    |   CXX     output/UNIX/opt/test/src/FakeLanguage.o
    |   CXX     output/UNIX/opt/test/src/FakeLogFile.o
    |   CXX     output/UNIX/opt/src/Kobo/FakeSymbols.o
    |   CXX     output/UNIX/opt/src/OV/OpenVarioMenu.o
    |   LINK    output/UNIX/bin/OpenVarioMenu
    

    Da kommt Map.o, File.o etc nicht vor



  • Dann mußt du diese noch zum passenden Makefile hinzufügen - das sollte dann build/ov.mk sein.

    Edit: Du mußt dann dort, wie bei den vorhandenen Zeilen, die Source-Dateien (.cpp) angeben.



  • Danke!!!!!!!! Das wars!



  • ein letztes kleines Problem bleibt.

    Diese Funktion

      static void ChangeConfigInt(const string &keyvalue, int value)
      {
        const Path ConfigPath("/boot/config.uEnv");
    
        ProfileMap configuration;
        Profile::LoadFile(configuration, ConfigPath);
        configuration.Set(keyvalue.c_str(), value);
        Profile::SaveFile(configuration, ConfigPath);
      }
    

    rufe ich so auf:

    ChangeConfigInt("rotation", 0);
    

    Der Eintrag sollte so aussehen:
    rotation=0

    er sieht aber so aus:
    rotation="0"

    Diese Funktion

      template<typename T>
      static void ChangeConfigString(const string &keyvalue, T value)
      {
        const Path ConfigPath("/boot/config.uEnv");
    
        ProfileMap configuration;
        Profile::LoadFile(configuration, ConfigPath);
        configuration.Set(keyvalue.c_str(), value);
        Profile::SaveFile(configuration, ConfigPath);
      }
    

    rufe ich so auf:

    ChangeConfigString("LANG", "en_EN.UTF-8");
    

    Der Eintrag sollte so aussehen:
    LANG =en_EN.UTF-8

    er sieht aber so aus:
    LANG ="en_EN.UTF-8"

    Wie kann ich dafür sorgen, dass die Anführungszeichen nicht eingetragen werden?



  • Das kannst (bzw. solltest) du direkt nicht ändern - die Funktion Write(const char *key, const char *value) in src/io/KeyValueFileWriter.cpp (welche von der Profile::SaveFile-Funktion aufgerufen wird), schreibt automatisch immer Anführungsstriche um den Wert herum:

    // write the value to the output file
    os.Format("%s=\"%s\"\n", key, value);
    

    Diese werden beim Einlesen von Read(KeyValuePair &pair) in src/io/KeyValueFileReader.cpp aber wieder herausgefiltert.



  • Das funktioniert bis auf einen Teil des Bootscreens, der interpretiert rotation="3" nicht und bleibt in der Standardausrichtung. Da muss ich mich mal auf die Suche machen, wie da ausgelesen wird, und muss versuchen das zu korrigieren.

    Der Teufel steckt mal wieder echt im Detail. Eine Datei, in die ich schreiben muss, existiert noch gar nicht. LoadFile macht dann Probleme. Ich muss also eine Überprüfung einbauen, ob die zu lesende Datei auch existiert.



  • Dieses Skript fragt die rotation für den erwähnten Teil des Bootscreens ab:

    #!/bin/sh
    
    # convert fbcon/rotate to degrees
    
    case "$(sed -n 's/^rotation=//p' /boot/config.uEnv)" in
    	"3")
    		rotation=90
    		;;
    	"2")
    		rotation=180
    		;;
    	"1")
    		rotation=270
    		;;
    	*)
    		rotation=0
    		;;
    esac
    exec /usr/bin/psplash --angle "${rotation}"
    

    Wenn in der /boot/config.uEnv rotation="3" steht, erhalte ich in der Shell mit "sed -n 's/^rotation=//p' /boot/config.uEnv"die Ausgabe "3". Ist dort rotation=3 eingetragen erhalte ich 3. 3 wird korrekt interpretiert, "3" nicht. Wie könnte ich das ändern, dass beides korrekt interpretiert wird??

    Update:
    die Zeile wie folgt geändert, löst das Problem:

    case "$(sed -n 's/^rotation=//p' /boot/config.uEnv | tr -d '"')" in
    


  • Wenn die Datei, in die geschrieben werden soll, noch nicht existiert, habe ich das mal zum Testen so gelöst:

      template<typename T>
      static void ChangeConfigString(const string &keyvalue, T value, const string &path)
      {
        const Path ConfigPath(path.c_str());
    
        ProfileMap configuration;
        Profile::SaveFile(configuration, ConfigPath);
        Profile::LoadFile(configuration, ConfigPath);
        configuration.Set(keyvalue.c_str(), value);
        Profile::SaveFile(configuration, ConfigPath);
      }
    

    die zusätzliche Zeile "Profile::SaveFile(configuration, ConfigPath);" einzufügen ist ja aber so noch keine saubere Lösung, da diese Zele nur ausgeführt werden sollte, wenn die Datei noch nicht existiert. Es müsste in etwa in der Weise formuliert werden:

      template<typename T>
      static void ChangeConfigString(const string &keyvalue, T value, const string &path)
      {
        const Path ConfigPath(path.c_str());
    
        ProfileMap configuration;
        if ("Datei ConfigPath existiert nicht")
        {
           Profile::SaveFile(configuration, ConfigPath);
        } 
        Profile::LoadFile(configuration, ConfigPath);
        configuration.Set(keyvalue.c_str(), value);
        Profile::SaveFile(configuration, ConfigPath);
      }
    

    Wie kann ich in der if-Abfrage denn überprüfen, ob die Datei existiert?



  • Du wirst wahrscheinlich eine Exception erhalten, wenn die Datei nicht existiert (oder andere Fehler beim Lesen auftreten), also fange sie

    try
    {
       Profile::LoadFile(configuration, ConfigPath);
    }
    catch (Exception &e)
    {
      // explicit do nothing
    }
    

    Es gibt wohl auch noch weitere IO-Funktionen z.B. in Open.hxx, aber selbst ein Überprüfen, ob die Datei existiert ist keine Garantie, daß diese auch gelesen werden kann!



  • noch mal herzlichen Dank!!!!

    Könnte man so den Wert von timeout auslesen?

      static void GetConfigInt(const string &keyvalue, int value, const string &path)
      {
        const Path ConfigPath(path.c_str());
    
        ProfileMap configuration;
        Profile::LoadFile(configuration, ConfigPath);
        configuration.Get(keyvalue.c_str(), value);
      }
    

    Aufrufen und interpretieren von timeoutvalue:

    GetConfigInt("timeout", timeoutvalue, "/boot/config.uEnv");
    unsigned remaining_seconds = timeoutvalue;
    

Anmelden zum Antworten