Build-Flags abhängige MACROS



  • Guten Morgen,

    ich habe eine c-lib, welche bestimmte public api methoden öffentlich macht (dllexport)

    und verwende folgende def.h:

    // Allow header to be used within C and C++ compilation units
    #ifdef __cplusplus
    #define BEGIN_CDECL extern "C" {
    #define END_CDECL   }
    #else
    //! if __cplusplus then: extern "C" {
    #define BEGIN_CDECL
    //! if __cplusplus then: }
    #define END_CDECL
    #endif
    
    
    #ifdef _WIN32
    #    ifdef ANSICLIB_EXPORTS
    #        define LIBRARY_API __declspec(dllexport)
    #    else
    #        define LIBRARY_API __declspec(dllimport)
    #    endif
    #elif
    #    define LIBRARY_API
    #endif
    

    und meine public api wird dann wie folgt definiert:

    BEGIN_CDECL
    
    LIBRARY_API void doSomethingPublic();
    
    END_CDECL
    

    nun möchte ich aber auch non-public methoden öffentlich machen (um sie zu testen) aber nur wenn das Flag TESTING beim bauen gesetzt ist:

    
    #ifdef TESTING
    
    BEGIN_CDECL
    LIBRARY_API void doSomethingPrivate();
    END_CDECL
    
    #else
    
    void doSomethingPrivate();
    
    #endif
    

    gibt hierfür ne elegantere variante?

    Danke euhc



  • Die Unittests z.b. gehören eigentlich zum Library-Projekt mit dazu. Der Test sollte also vor Auslieferung der Library erfolgen. Daher sollte es imo nicht nötig sein, Methoden nur fürs Testen public zu machen.



  • @It0101 sagte in Build-Flags abhängige MACROS:

    Die Unittests z.b. gehören eigentlich zum Library-Projekt mit dazu. Der Test sollte also vor Auslieferung der Library erfolgen. Daher sollte es imo nicht nötig sein, Methoden nur fürs Testen public zu machen.

    hmm.. ok d.h. ich muss für meine libs' immer eine unittest lib dependency mitliefern?

    EDIT:

    ok gut, hätte ich auch selbst drauf kommen können, test-folder und am besten (laut googleTest) das testframework mit liefern bzw. mitbauen



  • @SoIntMan sagte in Build-Flags abhängige MACROS:

    @It0101 sagte in Build-Flags abhängige MACROS:

    Die Unittests z.b. gehören eigentlich zum Library-Projekt mit dazu. Der Test sollte also vor Auslieferung der Library erfolgen. Daher sollte es imo nicht nötig sein, Methoden nur fürs Testen public zu machen.

    hmm.. ok d.h. ich muss für meine libs' immer eine unittest lib dependency mitliefern?

    "Mitliefern" muss nicht unbedingt sein, lediglich dokumentieren, dass - falls Tests gebaut werden sollen - eine zusätzliche Abhängigkeit von TestframeworkXYZ besteht. Bzw. das im Build-System entsprechend formulieren (if (testing_enabled) find_and_link_external_library(xyz) oder sowas).

    Zu deinem ursprünglichen Problem:

    So ein extern "C" muss nicht unbedingt ein Block sein, daher benötigst du nicht unbedingt die BEGIN_CDECL und END_CDECL, sowas hier geht auch:

    extern "C" void f();
    

    D.h. du könntest z.B. zentral Makros wie PUBLIC_LIBRARY_API und PRIVATE_LIBRARY_API definieren die das extern "C" ggfs. ebenfalls beinhalten. Diese klatscht du dann einfach vor die entsprechenden Funktionen.

    Ansonsten nochwas am Rande:

    #ifdef _WIN32
    #    ifdef ANSICLIB_EXPORTS
    #        define LIBRARY_API __declspec(dllexport)
    #    else
    #        define LIBRARY_API __declspec(dllimport)
    #    endif
    #elif
    #    define LIBRARY_API
    #endif
    

    __declspec(dllexport) ist meines Wissens MSVC-spezifisch. _WIN32 ist auch definiert, wenn man z.B. mit Clang/MinGW oder GCC/MinGW kompiliert. Der bessere Test wäre hier also #ifdef _MSC_VER.

    Wenn man für die anderen Compiler auch noch ein ähnliches Verhalten bzgl. Verfügbarkeit der Funktionen im DLL-Interface haben will, kann man, soweit ich mich entsinne, mit __attribute__((visibility("default"))) bzw. __attribute__((visibility("hidden"))) arbeiten. Die Funktionen werden bei GCC/Clang/MinGW alle per Default exportiert - also genau anders herum. Will man das MSVC-Verhalten replizieren, kann man dem Compiler z.B. -fvisibility=hidden mitgeben ("hidden" als Default wenn nichts angegeben wurde) und die zu exportierenden Funktionen mit __attribute__((visibility("default"))) markieren.

    Das jedoch nur aus meiner Erinnerung, du solltest das nochmal etwas genauer recherchieren, wenn du das tatsächlich unterstüzen willst (oder du lässt es einfach weg, dann werden eh alle Funktionen exportiert).



  • Ich schreibe mal kurz wie es bei uns ist ( wir nutzen CICD Pipelines von GIT ).

    Unsere CMakeLists haben eine Weiche drin, in der Tests optional mit konfiguriert werden oder nicht.

    • Der Entwickler pushed die Changes
    • In der Pipeline wird das CMakeLists mit dem Test-flag konfiguriert, d.h. es werden die Tests gebaut und ausgeführt.
    • Sind die Tests erfolgreich wird das CMakeLists ohne Test-Flag konfiguriert, d.h. in der eigentlichen ausgelieferten Library ist kein(!) Testcode enthalten und es gibt auch keine Abhängigkeiten


  • @Finnegan sagte in Build-Flags abhängige MACROS:

    So ein extern "C" muss nicht unbedingt ein Block sein, daher benötigst du nicht unbedingt die BEGIN_CDECL und END_CDECL, sowas hier geht auch:
    extern "C" void f();

    D.h. du könntest z.B. zentral Makros wie PUBLIC_LIBRARY_API und PRIVATE_LIBRARY_API definieren die das extern "C" ggfs. ebenfalls beinhalten. Diese klatscht du dann einfach vor die entsprechenden Funktionen.

    das is ne gute Idee, danke dir.

    @Finnegan sagte in Build-Flags abhängige MACROS:

    Wenn man für die anderen Compiler auch noch ein ähnliches Verhalten bzgl. Verfügbarkeit der Funktionen im DLL-Interface haben will, kann man, soweit ich mich entsinne, mit attribute((visibility("default"))) bzw. attribute((visibility("hidden"))) arbeiten. Die Funktionen werden bei GCC/Clang/MinGW alle per Default exportiert - also genau anders herum. Will man das MSVC-Verhalten replizieren, kann man dem Compiler z.B. -fvisibility=hidden mitgeben ("hidden" als Default wenn nichts angegeben wurde) und die zu exportierenden Funktionen mit attribute((visibility("default"))) markieren.

    das ist dann Plattformunabhänging?

    @It0101 sagte in Build-Flags abhängige MACROS:

    Unsere CMakeLists haben eine Weiche drin, in der Tests optional mit konfiguriert werden oder nicht.

    Der Entwickler pushed die Changes
    In der Pipeline wird das CMakeLists mit dem Test-flag konfiguriert, d.h. es werden die Tests gebaut und ausgeführt.
    Sind die Tests erfolgreich wird das CMakeLists ohne Test-Flag konfiguriert, d.h. in der eigentlichen ausgelieferten Library ist kein(!) Testcode enthalten und es gibt auch keine Abhängigkeiten

    das verwenden wir auch, und machen es ziemlich gleich, ich baue das ganze aber noch in VS2022 mit lokalen googleTest projekttemplate.



  • @SoIntMan sagte in Build-Flags abhängige MACROS:

    @Finnegan sagte in Build-Flags abhängige MACROS:

    D.h. du könntest z.B. zentral Makros wie PUBLIC_LIBRARY_API und PRIVATE_LIBRARY_API definieren die das extern "C" ggfs. ebenfalls beinhalten. Diese klatscht du dann einfach vor die entsprechenden Funktionen.

    das is ne gute Idee, danke dir.

    Ich denke es versteht sich, dass man in dem Fall die Makros auch abhängig von TESTING definiert. Da reicht dann tatsächlich nur ein Makro vor jedem API-Symbol.

    das ist dann Plattformunabhänging?

    Nein. __declspec(dllexport) ist das ja ebenfalls nicht. Das müsste man dann auch compilerspezifisch machen. Das wären halt weitere #ifdef/#elseifs für dein LIBRARY_API-Makro.

    Das ist aber nicht ungewöhnlich, dass es in Projekten solche Compiler- und Plattformweichen gibt. Auch wenn der Rest des Codes portabel gehalten ist. Gerade dafür macht man ja u.a. solche Makros wie LIBRARY_API, um das zu vereinheitlichen und die plattformspezifischen Sachen nicht überall im eigentlichen Code verteilt zu haben (sondern zentral an nur einer Stelle).

    Wie gesagt, es wird aber auch ohne den visibility-Kram funktionieren. Es werden dann nur eben alle Symbole durch die DLL exportiert. Da du zwischen "public" und "private" DLL-Interface unterscheidest, habe ich vermutet, dass dir das wichtig ist.



  • @Finnegan sagte in Build-Flags abhängige MACROS:

    Wie gesagt, es wird aber auch ohne den visibility-Kram funktionieren. Es werden dann nur eben alle Symbole durch die DLL exportiert. Da du zwischen "public" und "private" DLL-Interface unterscheidest, habe ich vermutet, dass dir das wichtig ist.

    perfekt, danke das schau ich mir definitiv an;)

    und die unit-teste mache ich dann direkt in der lib💪🏼


Anmelden zum Antworten