====== polymake Extensions ====== ===== What is an extension ===== A polymake extension is a collection of various bits and pieces of software that can be used together with the core stuff obtained from the distribution. An extension may enhance existing applications and/or define fully new, independent applications. In detail, an extension may contain any mix of: * rule files, thus allowing to define new properties, object types, all sorts or rules, methods, etc. * scripts and perl modules * C++ clients and class libraries ===== Starting an own extension ===== - Choose a location on your computer (or a network share) where you have write permissions; let's name it ''my_ext'' in the examples below.\\ If you are working with a git working copy of polymake, please make sure that your new directory is **outside** the source tree. - In an interactive polymake session, execute the commands:\\ ''%%found_extension "~/my_ext";%%''\\ ''%%extend_application "~/my_ext", "APP_NAME";%%''\\ where //APP_NAME// is the name of an existing application you are going to enhance. What has happened? polymake has created a folder ''my_ext'' (if it did not exist before) and within it a whole hierarchy of subfolders, having the same structure as the core applications:\\ ''apps/APP_NAME/rules''\\ ''apps/APP_NAME/scripts''\\ ''apps/APP_NAME/src''\\ and so on. Now it's upon you to populate it with new stuff. ''polymake'' has also created two directories \\ ''include'' and \\ ''build.''\\ in ''my_ext''. The first contains links to the header directories in ''apps/polytope/include'', the second will later contain the compiled libraries. You should not put any stuff there yourself. The absolute path to the top directory ''my_ext'' is stored in your custom variable ''@extensions'', so that from now on everything you put in this extension is automatically available as if it were defined in the core distribution. If you are going to define new rules, please remember that one of the rule files should be called ''main.rules'', which will be loaded by ''polymake'' at the very start of the session. For instance, if you want to use a new rule file called ''my_rules.rules'', the file ''my_ext/apps/APP_NAME/rules/main.rules'' should contain the following lines: INCLUDE my_rules.rules If you have written some C++ clients, they will be automatically compiled at the beginning of the next interactive session; however, later changes must be compiled manually by invoking\\ ''make -C ~/my_ext''. ===== Adding more applications to the same extension ===== You repeat the same command ''extend_application'' as described above, specifying the same extension directory. To create a really new application from scratch, execute the command\\ ''%%found_application "~/my_ext", "APP_NAME";%%'' \\ Again, it will create a folder hierarchy rooting at ''my_ext/apps/APP_NAME''. After having composed the rules and/or clients, you may add the ''APP_NAME'' to the [[:user_guide:howto:shell_custom#custom_variables|custom variable]] ''@start_applications'', so that you'll have your new application at hand in every interactive session. ===== Configuring an extension ===== If your extension depends on third-party software packages which need to be installed separately, you'll have to provide some auto-configuration routines in the rules. To resolve dependencies on autonomous programs, you can use all the fancy tools available in the "standard" rules: custom variables, ''CONFIGURE'' clauses, utilities like ''find_location'', ''find_program'', etc. In the case your extension needs a third-party library to build the C++ clients, you should provide a pre-build configuration procedure performing some preparations and sanity checks like adding compiler and linker flags necessary to find this library, asserting that its version is not too old for you, etc. All this is done in a script ''configure.pl'' located in the ''support'' directory of your extension. For this purpose, every extension gets at its birth a personal copy of a script template ''configure.pl.template''. You should edit it, filling the stubs of the functions with appropriate actions, introduce configuration options, if needed, and finally rename the script into ''configure.pl''. Then this script will be executed immediately during the [[#using_other_people_s_extensions|extension import]] as well as each time one runs the interactive command ''reconfigure_extension''. All clients in the extension are recompiled after each reconfiguration, at the latest at the beginning of the next polymake session. The script template contains comments describing the purpose and signature of each mandatory function; you may also want to look for the examples into the configuration scripts of extensions bundled with polymake. At your disposal are all utilities from the module ''perllib/Polymake/Configure.pm'' and all core configuration variables, both defined in the package ''Polymake::Configure''. The extension configuration script is interpreted in a separate package; please, don't change into other package within the script. Also be aware that the extended perl syntax (like namespace mode) is not allowed for the configure script. The outcome of a successful run of the configuration script is a list of variable assignments, which are stored in the file ''build.ARCH/conf.make'' in your extension which is included at each subsequent build. These variables can be referred to in custom ''make'' rules placed in ''Makefile.inc'' next to your clients; besides this, the script may directly add values to standard variables like ''CXXflags'' or ''Libs''. If your extension has [[#relations_between_extensions|prerequisites]] with their own configuration scripts, all their ''make'' variables are available in your extension build as well. In a complex scenario when the build process //and// the rules share some configurable paths or options, a rulefile can access the configured ''make'' variables of the own extension and all prerequisites by calling a special function ''load_extension_config_vars'' in its CONFIGURE clause. It is advisable to copy all necessary values into custom variables, as to avoid expensive parsing of makefiles in each polymake session. ==== Example ==== custom $path_to_something; CONFIGURE { my $vars=load_extension_config_vars(); $path_to_something=$vars->{SOME_DIR}; 1 # signal success } where the script ''configure.pl'' is supposed to contain (among others) the following fragments: @make_vars=qw( SOME_DIR ); sub proceed { $SOME_DIR=find_something() or die "can't find an important thing!\n"; } ===== Sharing an extension with other people ===== There are three possible ways to make your extension available to other people, which may also be arbitrarily combined: - If you have writing access to the polymake core installation (or can ask your sysadmin for assistance), that is available to other users on your computer or local network, you may install your extension right there:\\ ''make -C ~/my_ext install ExtensionName=EXTNAME''\\ This will create a subdirectory ''ext/EXTNAME'' under the top installation directory of polymake (which is stored in the variable ''$InstallTop'', by the way). Omitting the ''ExtensionName'' argument in the ''make'' command will install your extension under ''ext/my_ext''. - If you have collaborators developing your extension, you may keep it in a version-controlled repository. If you choose subversion, polymake will even automatically commit all automatically generated files and create ''svn:ignore'' attributes whenever needed. To fully enjoy the polymake support for subversion, you should register the top directory ''~/my_ext'' prior to calling any ''found_extension'' or ''extend_application'' commands. - If you want to bring your extension to broader audience, you may create a tarball starting at ''~/my_dir'' (but excluding the ''Makefile'' and any ''build.*'' folders) and make it available for download. In any case, people using your extension will eventually produce data files depending on it. Especially if you introduce new properties, object types, or applications, anybody not having access to your extension won't even be able to load a data file containing any of your specific features. To clearly distinguish them from the core features, each publicly available extension must have a unique identifier, also called URI. Although the form of the URI can't be strictly prescribed, we recommend a URL-like string roughly pointing in the direction of your website. e.g.:\\ ''%%"http://www.your.domain/polymake/extension/EXTNAME"%%'' The URI of your choice must be stored in the description file ''%%~/my_ext/polymake.ext%%''. This file is created by ''found_extension'' command and already contains a tentative URI starting with ''%%file:///%%''. Please replace it with an URI of your choice. Don't forget to submit the description file into the repository if you are using any. From now on each XML data file containing any of the extension-specific features will bear an additional ''ext'' attribute showing your URI. ===== Documentation ===== As your extension keeps growing, you'll want to create the documentation HTML pages to have a better overview of all the new features at hand. This can be done very easily with the script ''generate_docs'' shipped with polymake. Just call it from the interactive session like this: ''%%script("generate_docs", "%%//OUT_DIR//%%");%%'' Then you'll obtain the complete set of documentation pages describing the standard system //and// all loaded extensions, rooted at the given directory //OUT_DIR//, which you can load directly into your web browser or deploy to your local webserver. Please note that the extensions are not described on separate pages; instead, the properties, functions, etc. introduced in extensions are listed together with the corresponding standard features, as usual arranged by applications and object types. This behavior is implemented purposely, as it fully matches the seamless style of integrating extensions in the standard system. ===== How to make other people aware of your work ===== Uncomment the CREDIT section in the description file ''%%my_ext/polymake.ext%%'' and put few lines there, including your name, your homepage URL, as well as copyright notice, a short description of the features implemented in your extension, a citation of your main article about it, or whatever else you'll find appropriate to mention. Then this text will be displayed in each session as soon as a rule or function from your extension is called; the abbreviated form of your credit note will be also stored in each XML data file containing some of extension-specific object properties. In the case of a large team working together on an extension individual contributions may still be distinguished by usual [[user_guide:extend:rulefiles#credits_and_help|credit notes]] embedded in the rulefiles; then the credit note of the entire extension will be assigned by default to all rules and functions lacking individual credit notes. ===== Managing changes in data model ===== In the course of time you may change the data representation or rename properties introduced in your extension. These changes may render your old data files useless, as polymake won't be able to load them any more. To be able to recover the old files automatically, you should make use of //versioning//. To this end, you adopt some numbering scheme and append the current version number to the URI of your extension, like this: ''http://www.your.domain/polymake/extension/EXTNAME#1.0'' (recall that this is stored in the description file ''polymake.ext'' in the top folder of your extension). Then, each time you are introducing an incompatible change in your extension, you bump the version number (for example up to 1.1) and create a transformation stylesheet (XSLT) ''xml/upgrade-1.1'' . There are some lines that need to be present in any transformation sheet. Here is an example [...] Replace ''[...]'' with transformation rules for your extension. A simple transformation rule could be the following: NEW_PROPERTY This code just renames the property ''OLD_PROPERTY'' to ''NEW_PROPERTY'', leaving everything else invariant. Note, however, that this would apply to any occurrence of ''OLD_PROPERTY'', so if this property name also occurs somewhere else (e.g. in another application, or as a property of some other object) then those will be changed as well. So in this case make sure that your rule only matches the occurrence in your extension. The standard polymake distribution already contains several transformation stylesheets which can be used as a source of inspiration. When polymake loads a very old data file lying behind several version bumps, all transformations between its version and the current version are applied in the proper (ascending) order; thus each transformation stylesheet should only contain converting operations specific for a single version bump. ===== Writing testcases ==== It is always a good idea - especially if your extension is large - to write unit tests for your code. Those are essentially small examples which test individual rules and functions. One advantage of this is that you will quickly notice if a change in your code (or in a new polymake release) breaks something in your extension. Polymake offers a convenient set of tools for this, you can find a full description [[user_guide:extend:unit_tests|here]]. ===== Using other people's extensions ===== Depending on the way of distribution (as described above), you may have to check out the extension from a repository or download a tarball and unpack it. In any case the concluding step will be \\ ''%%import_extension "~/my_ext";%%''\\ called in a interactive session. Some extensions may ask for prerequisite libraries provided by third parties, necessary to compile the client functions. Such an extension will provide a configuration script which tries to automatically locate the required libraries and prepare the compilation process to use them. If the automatic recognition fails, the extension will be put in a disabled (unconfigured) state. You will see a (hopefully intelligible) error message explaining what exactly has been missing and how you can remedy the problem. When you have installed the required third-party libraries, or decided to turn down some optional part of the extension functionality, you can try to reactivate it using the command ''reconfigure_extension''. Depending on the style in which the extension configuration script is written, you might have to supply some options as string arguments to this command, or it will try to ask you some questions interactively. You can investigate the behavior calling \\ ''%%reconfigure_extension "~/my_ext", "--help";%%''\\ as well as trying the TAB completion or context-sensitive help (F1) when typing in this command. If nothing helps, you are invited to complain by the authors of the extension and asking them for assistance. Note that all configuration options can also be passed immediately to ''import_extension'' in the first place, as far as you can guess them up front. An active extension can also be reconfigured any time later, if needed. An extension can also be imported on demand, in the course of loading a data file containing an unknown extension URI. As soon as polymake encounters such a URI in the data file, it stops the loading procedure and asks you for the location where the extension resides. If you have no idea where to obtain the extension right now or simply don't want to bother installing it, you should type in ''stop'' (thus interrupting the loading process) or ''skip'' (loading only standard properties). In the latter case a backup copy of the data file is created. Your decision to despise this particular extension is remembered until the end of the interactive session; should you change your mind later, you'll have to restart polymake. You can stocktake your imported and configured extensions at any time using the interactive shell command\\ ''show_extensions;'' ===== Relations between extensions ===== Extensions may build upon each other, establishing dependence relations similar to software packages installed on your computer. The relations between extensions are described in dedicated sections of description files ''polymake.ext''. Every section contains one or more URIs of related extensions, separated with white spaces or distributed over several lines. An empty line marks the end of a section, similar to [[user_guide:extend:rulefiles]]. ? ''REQUIRE'' URI URI#version ... :: List of prerequisite extensions. In order to be able to import this extension, you must have imported all prerequisites up front. An optional version number expresses an additional requirement to have the specified extension in the given version or newer. .. A prerequisite bundled extension is specified using its short URI ''bundled://NAME//''. ? ''REPLACE'' URI ... :: List of obsolete URIs assigned earlier to this extension as well as to other old extensions merged with this one. You may also invent an abstract URI designating a feature provided by this extension and some alternatives. Then other extensions depending on this feature can list this abstract URI among their prerequisites. Any extension providing this URI as REPLACEment will successfully fulfill the role of that prerequisite. .. Bundled extensions may also have a REPLACE section if they were initially born as independent extensions and only later became part of polymake distribution. ? ''CONFLICT'' URI ... :: List of extensions which can't be imported together with this one. Additional remarks about prerequisite extensions: * As long as any prerequisite is disabled due to configuration script failure, the dependent extension will stay in disabled state as well. A successful reconfiguration of all prerequisites might automatically re-activate the dependent extension as well, unless it is equipped with its own configuration script. * Rulefiles of the dependent extension may refer to all property types, object types, user functions, and other features defined in the rulesfiles of prerequisite extensions without any constraints. C++ clients may include header files from prerequisite extensions as if they were directly located in the dependent extension. It is forbidden, however, to have client source files and header files of identical names in the prerequisite extensions and dependent extension. * polymake may automatically establish dependence relations to bundled extensions when the rulefiles of your extension instantiate C++ class or function templates involving types defined in that bundled extensions. As these relations are manifested in the description file ''polymake.ext'' distributed with your extension, all future users of your extension will need to enable that bundled extensions as well. You might want to revise the REQUIRE section of your extension prior to exposing it to the public. ===== Getting rid of an extension ===== One nice day you might suddenly want to get rid of an extension. The reason may be that you aren't interested in it any more, or that its functionality has silently moved into the standard distribution or another extension. The most comfortable way is to use the command ''obliterate_extension'' . It deletes all traces of the extension in your polymake settings. Be aware, however, that in the current interactive session you still have the pieces from the discarded extension loaded and ready-to-use. Thus, to avoid confusion, you should quit the session as soon as possible after using this command. Note also that you can't obliterate an extension as long as other registered extensions depend on it as a prerequisite. If you later try to load a data file referring to the URI of the obliterated extension, polymake will ask you, as usual, to enter its installation directory. If you are sure that in the meanwhile all the stuff has migrated into the standard distribution and/or other (already loaded) extensions, you should respond with the magic word ''ignore'' .