Udostępnij za pośrednictwem


Przewodnik po stylu narzędzia CMake

Oczekujemy, że wszystkie skrypty narzędzia CMake, które są albo:

  • scripts/ W katalogu lub
  • vcpkg-* W porcie

należy postępować zgodnie z wytycznymi określonymi w tym dokumencie. Istniejące skrypty mogą nie być jeszcze zgodne z tymi wytycznymi; oczekuje się, że będziemy nadal aktualizować stare skrypty zgodnie z tymi wytycznymi.

Te wytyczne mają na celu stworzenie stabilności w naszych skryptach. Mamy nadzieję, że ułatwią one zgodność zarówno do przodu, jak i z poprzednimi wersjami.

Wytyczne

  • Z wyjątkiem parametrów out-parameters, zawsze używamy cmake_parse_arguments() zamiast parametrów funkcji lub odwołując się do ${ARG<N>}.

    • Nie musi to być zgodne z instrukcjami "script-local helper functions"

      • W takim przypadku parametry pozycyjne powinny być umieszczane w deklaracji funkcji (zamiast używania ${ARG<N>}), i powinny być nazwane zgodnie z regułami lokalnymi (tj. snake_case).
      • Wyjątek: parametry pozycyjne, które są opcjonalne, powinny mieć nazwę za pośrednictwem set(argument_name "${ARG<N>}")metody , po sprawdzeniu ARGCwartości .
    • Parametry wychodzące powinny być pierwszym parametrem funkcji. Przykład:

      function(format out_var)
        cmake_parse_arguments(PARSE_ARGV 1 "arg" ...)
        # ... set(buffer "output")
        set("${out_var}" "${buffer}" PARENT_SCOPE)
      endfunction()
      
  • Nie ma żadnych nieparzysty ani nieużywanych argumentów. Zawsze sprawdzaj wartość ARGN lub arg_UNPARSED_ARGUMENTS. FATAL_ERROR jeśli jest to możliwe, WARNING w razie potrzeby w celu zapewnienia zgodności z poprzednimi wersjami.

  • Wszystkie cmake_parse_arguments muszą używać polecenia PARSE_ARGV.

  • Wszystkie foreach pętle muszą używać IN LISTSpętli , IN ITEMSlub RANGE.

  • Zmienne ${ARGV} i ${ARGN} nie są wnioskowane, z wyjątkiem przydatnych komunikatów dla użytkownika.

    • (tj. message(FATAL_ERROR "blah was passed extra arguments: ${ARGN}"))
  • Zawsze używamy funkcji, a nie makr ani kodu najwyższego poziomu.

    • Wyjątek: "script-local helper macros". Czasami pomocne jest zdefiniowanie małego makra. Należy to zrobić oszczędnie, a preferowane powinny być funkcje.
    • Wyjątek: vcpkg.cmake's find_package.
  • Skrypty w drzewie skryptów nie powinny wymagać obserwowanych zmian w ramach normalnego działania.

    • Przykładowe naruszenie: vcpkg_acquire_msys() ma zakodowane pakiety i wersje, które wymagają aktualizacji w czasie z powodu upuszczania starych pakietów w projekcie MSYS.
    • Przykładowy wyjątek: vcpkg_from_sourceforge() zawiera listę dublowania, które wymagają konserwacji, ale nie ma zauważalnego wpływu na osoby wywołujące.
  • Reguły cudzysłów: istnieją trzy rodzaje argumentów w CMake — bez cudzysłów (), cudzysłowie (foo(BAR)foo("BAR")) i nawias (foo([[BAR]])). Postępuj zgodnie z następującymi regułami, aby poprawnie cytować:

    • Jeśli argument zawiera rozszerzenie ${...}zmiennej , musi być cytowany.

      • Wyjątek: rozszerzenie zmiennej "splat", gdy jedna zmienna zostanie przekazana do funkcji jako wiele argumentów. W takim przypadku argument powinien po prostu mieć wartość ${foo}:

        vcpkg_list(SET working_directory)
        if(DEFINED "arg_WORKING_DIRECTORY")
          vcpkg_list(SET working_directory WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}")
        endif()
        # calls do_the_thing() if NOT DEFINED arg_WORKING_DIRECTORY,
        # else calls do_the_thing(WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}")
        do_the_thing(${working_directory})
        
    • W przeciwnym razie, jeśli argument zawiera jakiekolwiek sekwencje ucieczki, które nie \\są , \"lub \$, argument musi być argumentem cytowanym.

      • Na przykład: "foo\nbar" musi być cytowany.
    • W przeciwnym razie jeśli argument zawiera \argument , lub "$, argument powinien być nawiasem kwadratowym.

      • Przykład:

        set(x [[foo\bar]])
        set(y [=[foo([[bar\baz]])]=])
        
    • W przeciwnym razie, jeśli argument zawiera znaki, które nie są alfanumeryczne lub _, argument powinien być cytowany.

    • W przeciwnym razie argument powinien być bez cudzysłów.

    • Wyjątek: argumenty typu if() <variable|string> powinny być zawsze cytowane:

      • Oba argumenty operatorów porównania — EQUAL, STREQUAL, VERSION_LESSitp.

      • Pierwszy argument do MATCHES i IN_LIST

      • Przykład:

        if("${FOO}" STREQUAL "BAR") # ...
        if("${BAZ}" EQUAL "0") # ...
        if("FOO" IN_LIST list_variable) # ...
        if("${bar}" MATCHES [[a[bcd]+\.[bcd]+]]) # ...
        
      • W przypadku wyrażeń pojedynczych i innych typów predykatów, które nie przyjmują <variable|string>, użyj normalnych reguł.

  • Brak parametrów "wskaźnik" lub "wyjęcie" (gdzie użytkownik przekazuje nazwę zmiennej, a nie zawartość), z wyjątkiem prostych parametrów wyjściowych.

  • Nie zakłada się, że zmienne są puste. Jeśli zmienna ma być używana lokalnie, musi być jawnie zainicjowana, aby była pusta set(foo "") , jeśli jest zmienną ciągu, a vcpkg_list(SET foo) jeśli jest zmienną listy.

  • set(var) nie należy używać. Użyj unset(var) polecenia , aby usunąć ustawienie zmiennej, set(var "") aby ustawić ją na pusty ciąg i vcpkg_list(SET var) ustawić ją na pustą listę. Uwaga: pusty ciąg i pusta lista są tą samą wartością;jest to różnica notacyjna, a nie różnica w wyniku

  • Wszystkie zmienne, które mają być dziedziczone z zakresu nadrzędnego w granicach interfejsu API (tj. nie funkcji pliku lokalnego), powinny być udokumentowane. Wszystkie zmienne wymienione w plikach Triplet są uznawane za udokumentowane.

  • Parametry wychodzące są ustawiane tylko w PARENT_SCOPE parametrach i nigdy nie są odczytywane. Zobacz również pomocnik z_vcpkg_forward_output_variable() do przekazywania parametrów za pośrednictwem zakresu funkcji.

  • CACHE Zmienne są używane tylko w przypadku zmiennych globalnych, które są współużytkowane wewnętrznie między silnie powiązanymi funkcjami i stanem wewnętrznym w ramach jednej funkcji, aby uniknąć duplikowania pracy. Powinny one być używane bardzo oszczędnie i powinny używać prefiksu Z_VCPKG_ , aby uniknąć kolizji z dowolnymi zmiennymi lokalnymi, które byłyby zdefiniowane przez dowolny inny kod.

    • Przykłady:
      • vcpkg_cmake_configure's) Z_VCPKG_CMAKE_GENERATOR
      • z_vcpkg_get_cmake_vars's) Z_VCPKG_GET_CMAKE_VARS_FILE
  • include()s są dozwolone tylko w elemecie ports.cmake lub vcpkg-port-config.cmake.

  • foreach(RANGE)Argumenty "zawsze muszą być liczbami naturalnymi i <start> zawsze muszą być mniejsze niż lub równe <stop>.

    • Należy to sprawdzić w następujący sposób:

      if("${start}" LESS_EQUAL "${end}")
        foreach(RANGE "${start}" "${end}")
          ...
        endforeach()
      endif()
      
  • Wszystkie skrypty oparte na portach muszą być używane include_guard(GLOBAL) , aby uniknąć wielokrotnego dołączania.

Wersje narzędzia CMake do wymagania

  • Wszystkie skrypty narzędzia CMake, z wyjątkiem vcpkg.cmake, mogą przyjąć wersję narzędzia CMake, która jest obecna w elemecie cmake_minimum_required ports.cmake.
    • Powinno się to cmake_minimum_required pojawić za każdym razem, gdy nowa wersja narzędzia CMake zostanie dodana do vcpkgTools.xmlprogramu , tak jak w cmake_minimum_required przypadku wszystkich plików pomocnika CMakeLists.txt .
  • vcpkg.cmake musi przyjąć wersję narzędzia CMake z powrotem do wersji 3.7.2 ogólnie
    • Określone funkcje i opcje mogą zakładać większą wersję narzędzia CMake; Jeśli to zrobią, pamiętaj, aby dodać komentarz do tej funkcji lub opcji z wymaganą wersją narzędzia CMake.

Zmienianie istniejących funkcji

  • Nigdy nie usuwaj argumentów w funkcjach innych niż wewnętrzne; jeśli nie powinny już nic robić, po prostu wziąć je tak normalnie i ostrzegać przed użyciem.
  • Nigdy nie należy dodawać nowego obowiązkowego argumentu.

Nazewnictwo zmiennych

  • cmake_parse_arguments: ustaw prefiks na "arg"

  • Zmienne lokalne mają nazwę z snake_case

  • Wewnętrzne nazwy zmiennych globalnych są poprzedzone prefiksem Z_VCPKG_.

  • Zewnętrzne eksperymentalne nazwy globalnych zmiennych są poprzedzone prefiksem X_VCPKG_.

  • Funkcje wewnętrzne są poprzedzone prefiksem z_vcpkg_

    • Funkcje, które są wewnętrzne dla jednej funkcji (tj. funkcji pomocnika) mają nazwę [z_]<func>_<name>, gdzie <func> jest nazwą funkcji, do której służy pomocnik, i <name> jak działa funkcja pomocnika.
      • z_ należy dodać do przodu, jeśli <func> nie ma z_elementu , ale nie nazywaj funkcji z_z_foo_barpomocniczej .
  • Publiczne zmienne globalne mają nazwę VCPKG_.