web-dev-qa-db-fra.com

Basculer entre le code source et les binaires précompilés

Nous avons une énorme quantité de bibliothèques dans notre application. Les bibliothèques sont écrites en c ++ ou c #. (Plate-forme: framework .net, windows, 64 bits) Tout compiler en tant que code source prend beaucoup de temps. Nous pensions passer à des binaires prédéfinis, mais nous aimerions tout de même laisser une possibilité de revenir au code source. En tant que système de contrôle de version, nous utilisons git, les builds peuvent être effectués par Azure devops. Peut configurer n'importe quel serveur personnalisé si nécessaire.

Quels sont les outils prêts à l'emploi pour la gestion des paquets et la possibilité de basculer facilement entre le code source et les binaires pré-construits? (Si les outils ne sont pas compatibles avec les deux langages de programmation - il est correct de spécifier un ensemble d'outils pour un seul langage.) Si de tels outils n'existent pas, ce que vous recommanderiez vous-même - quel type d'emballage utiliser, sur quel type de scripts écrire en haut de celui-là?

Est-il possible d'identifier les pauses Api/abi?

4
TarmoPikaro

Il y a plusieurs axes sur ce problème - la construction du code source, l'installation du paquet, les référentiels externes, les ruptures api/abi, la construction du système lui-même.

Tout d'abord vos exigences - êtes-vous intéressé uniquement par l'emballage et/ou également l'installation.

Pour l'emballage lui-même, il est possible d'utiliser par exemple les systèmes d'emballage suivants: nuget, conan, vcpkg, choco.

Très probablement, vous serez également intéressé non seulement par la publication des packages eux-mêmes, mais également par leurs symboles de débogage.

Pour Azure devops/debug Symboles, la documentation de publication peut être trouvée à partir des liens suivants, par exemple:

https://Azure.Microsoft.com/en-us/blog/deep-dive-into-Azure-artifacts/https://docs.Microsoft.com/en-us/nuget/create-packages/symbol-packages-snupkg

Conan (packaging c ++) pour le moment ne prend pas en charge la publication de symboles: https://github.com/conan-io/conan/issues/4047

Pour obtenir la distribution du code source, il est possible d'utiliser git lui-même. Les sous-modules Git permettent de créer une référence de référentiel git externe, mais une fois que vous avez ajouté un sous-module externe, vous devez utiliser un double commit pour tout changer - un git commit dans le sous-référentiel, un git commit pour mettre à jour le hachage git référencé à partir du référentiel maître.

Il existe en effet quelques solutions à ces problèmes comme: git imbriqué sans sous-modules:

Dépôts git imbriqués sans sous-modules?

=>

http://debuggable.com/posts/git-fake-submodules:4b563ee4-f3cc-4061-967e-0e48cbdd56cb

Si vous construisez cependant un référentiel principal avec des binaires prédéfinis au lieu de codes sources - dans la solution idéale, vous n'avez pas besoin de ce référentiel git externe, ce qui signifie également qu'aucun clone git/extraction de référentiel externe n'est nécessaire.

Ensuite, il est également possible d'avoir soit all-in-one solution ou plusieurs solutions, chacune compilée séparément.

Plus facile en effet d'avoir all-in-one solution, car c'est moins compliqué avec la compilation de solutions dépendantes.

Pour obtenir une génération de solution entièrement dynamique, il est par exemple possible d'utiliser cmake - il peut générer une solution en fonction des options préconfigurées utilisées à partir de cmake. (Voir cmake's "option").

cmake est en effet une bonne alternative pour C++ (prend en charge l'en-tête précompilé, accélère la construction de l'unité), mais peut-être pas si simple pour C # (difficile de trouver les paramètres nécessaires pour le configurer correctement).

Pour le moment (5.2020), nous n'avons pas trouvé de meilleure alternative à cmake, mais il existe de multiples outils et écosystèmes évoluant parallèlement à cmake, il faut donc observer ce que l'avenir pourrait apporter.

Puis concernant l'emballage. choco semble être un sous-ensemble de nuget - il étend nuspec avec ses propres balises xml prenant en charge la mise à jour logicielle. (pages Web référencées: https://chocolatey.org/ , https://docs.Microsoft.com/en-us/nuget/reference/nuspec )

Si vous souhaitez publier un package nuget ou même un package d'installation, il est possible d'utiliser le référentiel nuget (sans frais supplémentaires).

Si cela ne répond pas à vos besoins, il est également possible de mettre à niveau le serveur nuget vers le serveur choco, mais cela peut coûter quelque chose - voir les pages Web chocolatées.

Les ruptures Api/abi ne peuvent être observées à aucun niveau, jusqu'à ce qu'une erreur de compilation/lien se produise ou que l'application se bloque au moment de l'exécution - la seule alternative qu'il soit possible de faire - est de contrôler le versionnage de l'empaquetage lui-même - donc la version principale du package nuget (ou choco) nécessiterait une version supérieure de la version nuget dépendante (ou choco).

Si le référentiel principal est développé par les mêmes personnes que le référentiel enfant - alors les ruptures api/abi peuvent être effectuées par le développeur lui-même, mais si deux gits sont indépendants l'un de l'autre et développés par des équipes différentes - alors les ruptures api/abi peuvent se produire à tout moment de temps.

Le meilleur moyen de s'assurer que les dépôts sont cohérents - consiste à effectuer des tests unitaires sur le référentiel maître, ce qui vérifierait qu'aucune rupture api/abi ne se produit.

Théoriquement, si api/abi casse - le système de construction lui-même pourrait continuer avec deux alternatives de construction -

  1. suivre le référentiel principal avec le dernier référentiel enfant actif
  2. suivre le référentiel enfant sans construire le référentiel principal

La même mécanique pourrait être appliquée en utilisant des branches, par ex.

  1. "main git: master branch" + "child git: release/1.0 branch"
  2. "enfant git: branche principale"

Cela peut nécessiter d'observer non seulement deux référentiels, mais également de changer de branche en cas de pannes de longue durée. (Par exemple, l'équipe de développement de l'enfant git ne se soucie pas des interruptions de construction qui se produisent dans git principal)

Suspectez qu'il n'existe pas d'outils prêts à l'emploi à cet effet (veuillez laisser un commentaire si tel est le cas), car cela pourrait nécessiter de reconnecter des outils de deux chaînes de construction potentiellement différentes de référentiels git potentiellement différents, d'organisations potentiellement différentes.

Enfin, si vous voulez que votre application soit compatible avec les mises à jour logicielles, le téléchargement de la distribution nuget/choco peut être utilisé avec un serveur nuget/choco supplémentaire.

Voici un bon exemple de partie de téléchargement pour le paquet nuget: https://github.com/mwrock/NugetDownloadFeed

La création de packages d'installation est un problème un peu plus complexe - voir par exemple les liens suivants:

(Dans l'ordre meilleur-pire selon mon opinion)

1
TarmoPikaro

J'ai lu votre question comme disant que les dépendances sont en .Net ou C++; et vos versions de sortie finales sont .Net. Vous savez que NuGet est "l'outil" .Net standard pour tout ce qui concerne les dépendances.

Maintenant. Cela dépend de ce que exactement vous voulez avec votre pensée de "basculer" facilement entre la source et le binaire?

On ne distingue pas sur le serveur de build de sur la machine développeur. Vous voulez sûrement que les deux construisent à partir de binaires pour être aussi rapides que possible, mais je ne peux pas comprendre que je veuille du code source sur le serveur de construction: le code source est pour les humains, pas pour les machines.

Option 1. Vous voulez dire 'obtenir la vitesse de construction du binaire mais l'expérience de débogage de la source'

Vous pouvez y parvenir avec NuGet. Vous utilisez Azure pour pouvoir ajouter des tâches à vos builds de bibliothèque pour publier directement dans un flux Azure NuGet privé. Votre point de départ pour cela est

Qui te parle

  1. Configurer le flux
  2. Publier dans le flux
  3. Consommez les aliments

Nuget peut vous donner l'expérience complète du "code source lors du débogage" car Nuget publish peut inclure des symboles source. Ceci est couvert sur la même page à l'ancre,

Sur l'ordinateur du développeur, remplacez les dépendances sur les projets de la solution par des dépendances sur le package NuGet. Vous obtenez alors l'expérience de pépite normale de:

  • NuGet met en cache les fichiers .dll compilés à partir du flux sur votre machine
  • NuGet vous indiquera quand des mises à jour sont disponibles
  • Vous choisissez quand obtenir la dernière version; OR vous pouvez appliquer always-update-on-build; OR vous pouvez appliquer always-update-on-checkout.

Force update-on-checkout vous donnera l'expérience de style code source de toujours regarder le (presque) dernier code tout en ayant toujours la construction la plus rapide possible à partir du binaire. Vous pouvez forcer update-on-git-checkout en ajoutant un hook git post-checkout pour exécuter nuget update, de sorte que chaque git get latest obtienne simultanément la dernière de nuget. https://ddg.gg/example%20git%20oncheckout%20hook%20windows .

(Il peut être utile d'appliquer un chemin de récupération standard pour les bibliothèques sur les machines de développement, car les fichiers de symboles .Net incluront le chemin utilisé pour la dernière version. Cependant, cela demande un certain effort et un certain savoir-faire Windows pour reproduire les chemins sur les machines de développement utilisées par le serveur de construction.)

Option 2. Vous voulez dire 'pouvoir basculer facilement entre la construction à partir de la source et la construction à partir du binaire'

Il n'existe pas de solution prête à l'emploi pour cela, car il s'agit d'une exigence inhabituelle. L'approche "simple" consiste à avoir des projets et des solutions séparés. Au lieu de cela, demandez à nouveau ce que exactement essayez-vous d'accomplir?

Si vous voulez simplement être sûr de créer à partir de sources les plus récentes, l'option 1 résout déjà ce problème - en quelques secondes ou en quelques secondes - pour le serveur de compilation et les machines de développement, car vos flux Azure nuget contiendront toujours les toutes dernières versions. .

(En fait, si vous utilisez des tests automatisés, l'option 1 est mieux que la construction à partir de la source, car elle utilisait la 'source la plus récente qui construit et réussit les tests' plutôt que 'la chose la plus récente quelqu'un accidentellement enregistré'. )

Si vous voulez 'la source complète dans mon projet mais des builds rapides', cela peut se produire automatiquement: msbuild, comme cmake, ne reconstruira pas un projet s'il est déjà à jour. Cependant, les développeurs de Visual Studio se souviennent généralement de la frappe pour la reconstruction (= nettoyer + construire) au lieu de la construction. Si vous avez une tonne de dépendances, apprendre à changer cette touche peut vous faire gagner tout le temps d'attente. Le hic, c'est que si d'autres développeurs apportent beaucoup de changements, il est impossible d'éviter le temps d'obtention de la dernière source et de reconstruction.

Vous pouvez avoir différents fichiers de projet pour créer une machine de développement ou un serveur de génération. Maintenir cela sera un glissement sujet aux erreurs, donc vous devriez script la génération automatique des fichiers csproj du serveur de construction à partir des fichiers standard. Le serveur de construction peut alors obtenir les dépendances de nuget, tandis que la machine de développement utilise source et pousse également les mises à jour des bibliothèques construites avec succès vers le fil de nuget.

Commentaire: À quelle distance pouvons-nous nous rapprocher du meilleur des deux mondes?

Il est indéniable qu'avoir de grands projets avec de nombreuses dépendances introduit un coût que vous n'avez pas avec les petits projets. Vous payez le prix soit d'avoir un gros projet qui est lent à ouvrir et lent à construire; ou en cassant les builds (via nuget ou d'autres moyens) et en perdant l'accès simple instantané à tout le code source.

Les flux NuGet avec symboles offrent la tentative la plus courante et la plus simple de résoudre ce problème.

1
Chris F Carroll

Nous pensions passer à des binaires prédéfinis mais nous aimerions tout de même laisser la possibilité de revenir au code source

donc tout d'abord vous aurez besoin d'un système de construction, que je vous recommande d'utiliser cmake pour gérer votre source code et ses dépendances. Permet d'obtenir une configuration de test ici, et supposons que votre répertoire de travail ressemble à ceci:

project_folder
|-- lib
|   |-- LibA.cpp
|   |-- LibA.hpp
|-- tools
|   |-- conanfile.py
|   |-- conanfile.txt
|-- CMakeLists.txt
|-- main.cpp  

qu'est-ce qu'ils supposent être: CMakeLists.txt est votre fichier de configuration cmake, à gérer

Est-il possible d'identifier les pauses Api/abi?

et conanfile.py est votre recette, signifie ce dont vous avez besoin pour package et créer vos bibliothèques prédéfinies et conanfile.txt est votre fichier requis pour consommer vos bibliothèques pré-construites.

donc apparemment, je suggère également d'utiliser conan pour gérer vos bibliothèques pré-construites, ou aussi appelé comme packages.

Passons maintenant à mon exemple et comment l'utiliser: CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)

project(my_project LANGUAGES CXX)

add_library(LibA lib/LibA.cpp)

add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibA)

target_include_directories(LibA PUBLIC ${CMAKE_CURRENT_LIST_DIR}/lib)

Je vais m'en tenir à cpp dans mon exemple, mais pour votre .net framework, vous pouvez vérifier this ou this

Je définis donc simplement mon targets dans ces fichiers, et je déclare ses dépendances les unes avec les autres, avec le contenu suivant: main.cpp:

#include <iostream>
#include "LibA.hpp"


int main()
{
  printTesting();
  std::cout << "Hello World! again" << std::endl;
  return 0;
}

LibA.cpp:

#include <iostream>
#include "LibA.hpp"

void printTesting(void)
{
  std::cout << "Testing Something" << std::endl;
}

LibA.hpp:

#include <iostream>

void printTesting(void);

Je suppose simplement que vous n'êtes pas familier avec cmake : nous allons laisser cmake générer le Makefile pour nous, ou pour vous evtl. les .vcxproj si tu utilises .net générateur, mais je veux rester simple ici, donc nous allons configurer le projet et build les binaires.

mkdir ../build && cd ../build
cmake ../project_folder && make

vous obtiendrez vos LibA et ExecutableA, donc rien de spécial ici encore, juste que cmake s'occupe maintenant de vos dépendances, et evtl. reconstruisez-les si quelque chose a changé (par exemple new commits dans vos projets). avec conanfile.py comme ceci:

from conans import ConanFile, tools


    class LibAConan(ConanFile):
        name = "libA"
        version = "0.1"
        settings = "os", "compiler", "build_type", "Arch"
        description = "<Description of LibA here>"
        url = "None"
        license = "None"
        author = "None"
        topics = None

        def package(self):
            self.copy("*.a")

        def package_info(self):
            self.cpp_info.libs = tools.collect_libs(self)

tu veux:

cp ../project_folder/tools/conanfile.py && conan export-pkg . libA/0.1@myuser/testing

avec le nom de notre package est: libA in 0.1 version. myuser/testing est le canal, ce qui est intéressant en cas de compilation croisée pour plusieurs plates-formes cibles.

Nous avons créé le package réutilisable en appelant conan export-pkg, et ceci est mis en cache dans $HOME_DIR/.conan/data/libA/0.1/myuser/testing (ou vérifiez-le dans votre environnement: conan config home)

Evtl. vous voulez d'abord installer conan, alors vérifiez ceci guide d'installation ou ceci téléchargements et pour votre configuration spéciale: avec Azure devops

Ainsi, ces packages créés pourraient également être uploadés vers n'importe quel serveur_distant: $ conan upload libA/0.1@myuser/testing --all -r=my_remote_server (par analogie: comme git Push après la validation dans git).

Nous avons donc configured, built avec cmake et created et uploaded packages utilisant conan, vos collègues pourraient réutiliser les packages/binaires prédéfinis en définissant leurs exigences dans pythonfile.txt :

[requires]
libA/0.1@myuser/testing

[generators]
cmake

et ils pourraient faire:

mkdir ../build_using_prebuild && cd ../build_using_prebuild && cp ../project_folder/tools/conanfile.txt . && conan install -g deploy . -r my_remote_server

conan recherchera ce package requis et evlt. téléchargez-le depuis my_remote_server

S'ils exécutent maintenant cmake ../project_folder && make, ces paquets prédéfinis seront utilisés, au lieu de compiler le src à partir de zéro.

Bien sûr, je vous recommande d'automatiser ces étapes dans Azure, mais je suppose que vous avez compris comment build system et package manager pourraient être utilisés pour orchestrer votre construire.

0
dboy

Nous pensions passer à des binaires prédéfinis, mais nous aimerions tout de même laisser une possibilité de revenir au code source

Pour C++, vous pouvez utiliser Conan (je suis sûr qu'il existe également d'autres outils similaires mais je ne les ai pas utilisés). Vous pouvez télécharger vos packages prédéfinis sur un serveur et demander à vos développeurs de les installer en cas de besoin. Ce serait aussi simple que d'ajouter des dépendances à la liste des exigences d'un conanfile.py que vous conservez dans le cadre de vos projets. Et pour construire à partir de sources (par exemple, lorsque les binaires sont absents de votre serveur), vous pouvez ajouter un --build à l'option conan install commande (qui installe les dépendances de votre projet).

pour basculer facilement entre le code source et les binaires pré-construits

Essayez-vous de basculer entre le maintien d'une dépendance dans l'arborescence des sources de votre projet et la liaison avec le binaire? Je ne vois aucun avantage à long terme à l'avoir dans votre arborescence des sources si vous utilisez un gestionnaire de paquets. Bien sûr, il peut être un peu plus pratique de modifier le code source de la dépendance si elle fait partie de l'arborescence des sources (en n'ayant pas à basculer entre les répertoires par exemple), mais je dirais que c'est probablement plus organisé et efficace sur le long terme run pour changer la dépendance séparément dans son propre projet. (et dans Conan, vous pouvez utiliser des "utilisateurs" et des "canaux" pour gérer ces versions personnalisées de bibliothèques tierces)

Est-il possible d'identifier les ruptures Api/abi

Le meilleur moyen de gérer cela à mon avis est de garder une trace de vos versions de dépendance. Encore une fois, un gestionnaire de packages comme Conan peut vous aider puisque vous spécifiez la version de la dépendance dans vos exigences.

Un avantage de l'utilisation de Conan serait que vous pouvez également ajouter des dépendances de construction qui introduisent votre environnement. Par exemple, CMake peut être une dépendance de construction. Ainsi, votre package installerait d'abord la version de CMake spécifiée, puis le reste de vos dépendances générées avec CMake. Cela rend votre gestion DevOps beaucoup plus facile.

0
pooya13

Pour les projets C++, vous pouvez vérifier CMake pour votre but. Vous pouvez conserver différentes options de construction comme 1) construire tout le code source 2) Construire les sous-modules dans des bibliothèques une fois et les réutiliser pour le projet principal. Le dernier CMake prend également en charge les en-têtes pré-compilés. Vous pouvez vérifier cela également pour réduire les temps de compilation.

Conan et vcpkg deux gestionnaires de packages sont disponibles pour les modules C++

0
sanoj subran