** ** Source tree organization ** ****************************************************** There is at least 5 sub-projects in the tree: - XBT: eXtended Bundle of Tools (low-level toolbox: logging, datatypes). - SURF: a SimUlation aRtiFact. This is the simulation kernel. - MSG: originally MetaSimGrid, MSG is a simple distributed application simulator. - GRAS: Grid Reality And Simulation (message passing API with two implementations allowing to compile programs on top of the simulator or for the real life without code modification) - AMOK: Advanced Metacomputing Overlay Kit (high level toolbox; Grid application elements such as distributed database, topology discovery service, and so on) They are all in the same tree because they are complementary tools and having all of them in the same package makes the installation easier for end-users. Moreover, it enables to share the compilation chain and eases the development. The tree is not splited on projects, but on file finality: include/ -> all *public* headers include/xbt/*.h -> one file per module include/gras.h -> file including all modules headers (same for xbt instead of gros) src/Makefile.am -> main makefile. All projects should fit in only one library (I mean 2, RL+SG), which is compiled here. Since all object.o files are placed here, you should choose the name of c files carfully to avoid conflict. src/gras/DataDesc -> typical project module src/gras/DataDesc/datadesc_interface.h -> visible to any GRAS modules; masked to the user and GROS/AMOK/SURF src/gras/DataDesc/datadesc_private.h -> visible only from this module So, the modules have 3 levels of publicity for their interface. Private, internal to GRAS, public. Of course, I try to keep as much stuff private as possible. src/include -> another location for protected headers. Used by SURF, and other should be converted, since this is the Right Thing. testsuite/ -> The more test the better. Same organization than src/ and include/ Tests are allowed to load some headers of the module they test. All tests should be listed in run_test.in so that they get run on 'make check'. They are not listed directly in the check_PROGRAMS part of the makefile because run_test knows about the gras logging features and relaunch with full details the failed tests. examples/ -> Supposed to be copy/pastable by the user, so keep it clear and avoid any kind of trick. In particular, do only include the public headers here. ** ** Indentation standard ** ***************************************************** Most files use the Kernighan & Ritchie coding style with 2 spaces of indentation. The indent program can help you to stick to it. :) ** ** Type naming standard ** ***************************************************** It may sound strange, but the type naming convention was source of intense discution between da GRAS posse members. The convention we came to may not be the best solution, but it has the merit to exist and leave everyone work. So please stick to it. - ???_t is a valid type (builded with typedef) - s_toto_t is a structure (access to fields with .) - s_toto is a structure needing 'struct' keyword to be used - e_toto_t is an enum - u_toto_t is an union - u_toto is an union needing 'union' keyword to be used - toto_t is an 'object' (struct*) Please to not call toto_t something else than an 'object' (ie, something you have to call _new and _free on it). Exemple: typedef struct s_toto {} s_toto_t, *toto_t; typedef enum {} e_toto_t; Moreover, only toto_t (and e_toto_t) are public. The rest (mainly s_toto_t) is private. If you see any part of the code not following this convention, this is a bug. Please report it (or fix it yourself if you can). ** ** Random bits about coding standards and portability ** ***************************************************** MALLOC: Don't use it, or you'll have to check the result (and do some dirty stuff on AIX). Use xbt_malloc (or even better, xbt_new) instead. SIZE_T If possible, avoid size_t and use unsigned long instead. If not, #include in all files manipulating size_t do cast it to unsigned long before printing (and use %lu) PRINTF pointer difference printf ("diff = %ld\n", (long) (pointer2 - pointer1)); ** ** Commenting the source: doxygen ** **************************************************** The global structure of the documentation is in doc/modules.doc The structure of each module (xbt, gras, etc) is in doc/module-.doc The structure of a module is in its public header. This way, you're sure to see all the public interface (and only it). The different parts of the interface are grouped using the @name construct, even if it's buggy. Since parts often get reordered, it's better to add numbers to the parts (so that users can see the intended order). The documentation of each type and macro are also in the public header since this is were they live. The documentation of each function must be in the C file were it lives. Any public element (function, type and macro) must have a @brief part. ** ** Using the logs ** **************************************************** Dans gras, tu ne te contente pas d'écrire des choses à l'écran, mais tu écris sur un sujet particulier (notion de canal) des choses d'une gravité particulière. Il y a 7 niveaux de gravité. trace: tracer les entrées dans une fonction, retour de fonction (famille de macros XBT_IN/XBT_OUT) debug: pour t'aider à mettre au point le module, potentiellement tres bavard verbose: quelques infos succintes sur les internals du module info: niveau normal, ton de la conversation warning: problème potentiel, mais auquel on a su faire face error: problème qui t'as empêché de faire ton job critical: juste avant de mourir Quand on compile avec -DNDEBUG (par défaut dans le paquet Debian), tout ce qui est '>= verbose' est supprimé au moment de la compilation. Retiré du binaire, killé. Ensuite, tu écris dans un canal particulier. Tous les canaux sont rangés en arbre. Il faudrait faire un ptit script qui fouille les sources à la recherche des macros XBT_LOG_NEW_* utilisées pour créer des canaux. Le dernier argument de ces macros est ignoré dans le source. Il est destiné à être la documentation de la chose en une ligne. En gros, ca fait: root +--xbt | +--config | +--dict | | +--dict_cursor | | +--dict_elm | | ... | +--dynar | +--set | +--log | +--module +--gras +--datadesc | +--ddt_cbps | +--ddt_convert | +--ddt_exchange | +--ddt_parse | +--lexer +--msg +--transport +--raw_trp (Je devrais tuer ce module, un jour) +--trp_buf +--trp_sg +--trp_file +--trp_tcp Et ensuite les utilisateurs peuvent choisir le niveau de gravité qui les interresse sur tel ou tel sujet. Toute la mécanique de logging repose sur des variables statiques dont le nom dépend du nom du canal. => attention aux conflits de nom de canal => il faut une macro XBT_LOG dans chaque fichier où tu fais des logs. XBT_LOG_NEW_CATEGORY: nouveau canal sous "root". Rare, donc. XBT_LOG_NEW_SUBCATEGORY: nouveau canal dont on précise le père. XBT_LOG_DEFAULT_CATEGORY: indique quel est le canal par défaut dans ce fichier XBT_LOG_NEW_DEFAULT_CATEGORY: Crèe un canal et l'utilise par défaut XBT_LOG_NEW_DEFAULT_SUBCATEGORY: devine XBT_LOG_EXTERNAL_CATEGORY: quand tu veux utiliser par défaut un canal créé dans un autre fichier. Une fois que ton canal est créé, tu l'utilise avec les macros LOG, DEBUG, VERB, WARN, ERROR et CRITICAL. Il faut que tu donne le nombre d'arguments après le nom de macro. Exemple: LOG2("My name is %s %s","Martin","Quinson") Si tu veux préciser explicitement le canal où écrire, ajoute un C devant le nom de la macro. Exemple: CCRITICAL0(module, "Cannot initialize GRAS") Toutes ces macros (enfin, ce en quoi elles se réécrivent) vérifient leurs arguments comme printf le fait lorsqu'on compile avec gcc. LOG1("name: %d","toto"); donne un warning, et donc une erreur en mode mainteneur. Enfin, tu peux tester si un canal est ouvert à une priorité donnée (pour préparer plus de débug, par exemple. Dans le parseur, je fais du pretty printing sur ce qu'il faut parser dans ce cas). XBT_LOG_ISENABLED(catName, priority) Le second argument doit être une valeur de e_xbt_log_priority_t (log.h). Par exemple: xbt_log_priority_verbose Voila sur comment mettre des logs dans ton code. N'hesite pas à faire pleins de canaux différents pour des aspects différents de ton code. En particulier, dans les dict, j'ai un canal pour l'ajout, le retrait, le netoyage du code après suppression et ainsi de suite. De cette façon, je peux choisir qui m'interresse. Pour utiliser les logs, tu déjà faire, non ? Tu colle sur la ligne de commande un ou plusieurs arguments de la forme --gras-log=" [+]" (ou sans " si t'as pas d'espace) chaque réglage étant de la forme: .thres= Les différents réglages sont lus de gauche à droite. "root.thres=debug root.thres=critical" ferme tout, normalement.