user_guide:extend:clients

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revisionBoth sides next revision
user_guide:extend:clients [2019/01/25 16:01] – ↷ Page moved from reference:clients to user_guide:extend:clients oroehriguser_guide:extend:clients [2021/01/12 15:38] – external edit 127.0.0.1
Line 296: Line 296:
   }   }
  
-Using a cached pointer allows to call function templates without injecting their definition body in the caller source code, so that they can be defined in a different application or bundled extension.  The function may also have several labeled alternative implementations selectable by preference lists.  The cached pointer is automatically following the changes introduced by user commands [[:general#preferences|prefer, prefer_now, and reset_preference]]. +Using a cached pointer allows to call function templates without injecting their definition body in the caller source code, so that they can be defined in a different application or bundled extension.  The function may also have several labeled alternative implementations selectable by preference lists.  The cached pointer is automatically following the changes introduced by user commands [[:user_guide:howto:shell_custom#preferences|prefer, prefer_now, and reset_preference]]. 
  
 There is, however, a restriction posed on the eligible functions: they must not have keyword arguments (perl::OptionSet), arguments with default values or explicit type parameters.  The reason for this restriction is that all this is processed in the perl layer which is bypassed when calling over a pointer. There is, however, a restriction posed on the eligible functions: they must not have keyword arguments (perl::OptionSet), arguments with default values or explicit type parameters.  The reason for this restriction is that all this is processed in the perl layer which is bypassed when calling over a pointer.
Line 303: Line 303:
 ==== Miscellaneous functions ==== ==== Miscellaneous functions ====
   ? ''%%var = perl::get_custom("name")%%''   ? ''%%var = perl::get_custom("name")%%''
-  :: Retrieve the value of a custom variable.  The name argument must start with the perl type designator ''$'', ''@'', or ''%'', matching the type of the custom variable.  The name must be fully qualified (exactly how it appears in the user's file ''customize.pl'').  If the custom variable is of an array or hash map type, the C++ local variable being assigned to must be of type ''perl::ListResult'' resp. ''perl::OptionSet''.+  :: Retrieve the value of a custom variable.  The name must be fully qualified with the package name unless it's defined in the package of the same application as this code belongs to.  If the custom variable is of an array or hash map type, the C++ local variable being assigned to must be of type ''perl::ListResult'' resp. ''perl::OptionSet''.
   ? ''%%var = perl::get_custom("name", "key")%%''   ? ''%%var = perl::get_custom("name", "key")%%''
   :: Retrieve the value of an element of a custom hash map variable.   :: Retrieve the value of an element of a custom hash map variable.
   ? ''%%perl::save_data("filename", var, "description");%%''   ? ''%%perl::save_data("filename", var, "description");%%''
-  :: Store an item of a data type known as a [[reference:rulefiles#type_definitions|property type]] (not a "big" object!) in an XML file.  The description string is optional.+  :: Store an item of a data type known as a [[user_guide:extend:rulefiles#type_definitions|property type]] (not a "big" object!) in an XML file.  The description string is optional.
   ? ''%%var = perl::load_data("filename");%%''   ? ''%%var = perl::load_data("filename");%%''
   :: Retrieve the data stored in an XML file created with ''save_data''.   :: Retrieve the data stored in an XML file created with ''save_data''.
Line 331: Line 331:
 The behavior of functions declared with or without ''User'' prefix is exactly the same; the only difference is that user functions appear in the TAB completion lists, as well as in the interactive help and on the reference documentation pages, while the "bare" functions stay invisible to the user (but she can still call the latter from the interactive shell or from scripts, if she knows about them).  All examples and explanations following below are equally applicable to both pairs of macros. The behavior of functions declared with or without ''User'' prefix is exactly the same; the only difference is that user functions appear in the TAB completion lists, as well as in the interactive help and on the reference documentation pages, while the "bare" functions stay invisible to the user (but she can still call the latter from the interactive shell or from scripts, if she knows about them).  All examples and explanations following below are equally applicable to both pairs of macros.
  
-''Function4perl'' is used to bind regular C++ functions.  It has two arguments: the first one is the address of the C++ function (like ''&cube''), the second one is a string defining the [[reference:polymorphic#signature|perl-side signature]] much like it is done in the rulefiles.+''Function4perl'' is used to bind regular C++ functions.  It has two arguments: the first one is the address of the C++ function (like ''&cube''), the second one is a string defining the [[user_guide:extend:polymorphic#signature|perl-side signature]] much like it is done in the rulefiles.
  
-''FunctionTemplate4perl'' is used to bind function templates.  It has only one argument, namely the string containing the [[reference:polymorphic#signature|signature]] and [[reference:polymorphic#attributes|optional attributes]] describing the return value.  The perl-side name specified in the signature must be identical to the C++ name.+''FunctionTemplate4perl'' is used to bind function templates.  It has only one argument, namely the string containing the [[user_guide:extend:polymorphic#signature|signature]] and [[user_guide:extend:polymorphic#attributes|optional attributes]] describing the return value.  The perl-side name specified in the signature must be identical to the C++ name.
  
 The perl-side arguments defined in the signature must match the parameters of the C++ function.  The matching rules are, however, flexible and allow for quite elaborate mapping between the perl and C++ worlds.  You are even allowed to map several perl signature to the same C++ function (by writing several ''Function'' macros with different signatures) or map one single perl signature to several C++ functions (by providing overloaded instances of the latter in your source code).  Below you can find the matching rules for all possible elements of a signature: The perl-side arguments defined in the signature must match the parameters of the C++ function.  The matching rules are, however, flexible and allow for quite elaborate mapping between the perl and C++ worlds.  You are even allowed to map several perl signature to the same C++ function (by writing several ''Function'' macros with different signatures) or map one single perl signature to several C++ functions (by providing overloaded instances of the latter in your source code).  Below you can find the matching rules for all possible elements of a signature:
Line 378: Line 378:
  
 ==== Injecting Rules into Clients ==== ==== Injecting Rules into Clients ====
-When an application is loaded, every client is processed like a mini-[[reference/rulefiles|rulefile]], after all regular rulefiles.  You can embed any perl code or special rules recognized by polymake directly into a client, using a macro+When an application is loaded, every client is processed like a mini-[[user_guide:extend:rulefiles|rulefile]], after all regular rulefiles.  You can embed any perl code or special rules recognized by polymake directly into a client, using a macro
   InsertEmbeddedRule("rule text\n"   InsertEmbeddedRule("rule text\n"
                      "extending over several lines\n"                      "extending over several lines\n"
Line 385: Line 385:
 In practice, only few use cases justify embedding into clients, because such rules are not easy to spot and every change would require a recompilation of the client library: In practice, only few use cases justify embedding into clients, because such rules are not easy to spot and every change would require a recompilation of the client library:
   * providing short pure perl overloaded function instances complementing the client functions defined in this client, e.g. convenience wrappers performing input and/or result transformations.   * providing short pure perl overloaded function instances complementing the client functions defined in this client, e.g. convenience wrappers performing input and/or result transformations.
-  * introducing [[reference/rulefiles#credits_and_help|credit notes]] specific for this client +  * introducing [[user_guide:extend:rulefiles#credits_and_help|credit notes]] specific for this client 
-  * imposing restrictions on the use of this client like [[reference/rulefiles#structuring_the_ruleset|REQUIRE_EXTENSION or REQUIRE_APPLICATION]].+  * imposing restrictions on the use of this client like [[user_guide:extend:rulefiles#structuring_the_ruleset|REQUIRE_EXTENSION or REQUIRE_APPLICATION]].
  
 Note that CREDIT and REQUIRE rules must precede the Function macros in the client source code in order to take effect on them. Note that CREDIT and REQUIRE rules must precede the Function macros in the client source code in order to take effect on them.
Line 392: Line 392:
 ==== Building and Debugging ==== ==== Building and Debugging ====
  
-As already mentioned at the very beginning, the client source code always resides in the application ''src'' directory.  It can only be built together with other clients of its application or extension.  Just call ''make'' at the top directory of the polymake source tree resp. of the extension.  Call ''make Debug=y'' if you are going to run it under the debugger. Take care to call the right client, i.e. the one located in the polymake/perl/ directory. You should call it from outside the directory.+As already mentioned at the very beginning, the client source code always resides in the application ''src'' directory.  It can only be built together with other clients of its application or extension.  Just run ''ninja -C build/Opt'' at the top directory of the polymake source tree resp. of the extension.  Run ''ninja -C build/Debug'' if you are going to run it under the debugger.
  
-When your client is called for the first time, it might require a new wrapper for transforming the arguments from perl representation to C++ and the results in the opposite direction.  This wrapper will be generated automatically, compiled on the fly, and loaded as a separate dynamic module.  Unless you set the custom variable ''$Verbose::cpp'' to 1 or higher, you won't notice anything but some delay in execution.  But, if your client is a function template, it will be really instantiated only now, so that some compiler errors might appear.  To fix the errors, you don't need to leave the running polymake session in most cases!  Just edit the sources of your client and repeat the call.  You will only have to quit the session if you make any changes in the glue declarations like ''Functions4perl''.+When your client is called for the first time, it might require a new wrapper for transforming the arguments from perl representation to C++ and the results in the opposite direction.  This wrapper will be generated automatically, compiled on the fly, and loaded as a separate dynamic module.  Unless you set the custom variable ''$Verbose::cpp'' to 1 or higher, you won't notice anything but some delay in execution.  But, if your client is a function template, it will be really instantiated only now, so that some compiler errors might appear.  To fix the errors, you don't need to leave the running polymake session in most cases!  Just edit the sources of your client and repeat the call.  You will only have to quit the session if you make any changes in the glue declarations like ''Function4perl''.
  
-When you quit the session later, after having fixed all compiler problems, the automatically created wrapper will be written into a separate source file, located in the subdirectory ''perl'' of the client's source directory.  Next time polymake is started, it will recompile the client together with the wrapper once again while loading the application.+When you quit the session later, after having fixed all compiler problems, the automatically created wrapper will be written into a separate source file, located in the subdirectory ''cpperl'' of the application.  Next time polymake is started, it will recompile the client together with the wrapper once again while loading the application.
  
-If the client belongs to the polymake source tree, or your extension is kept under SVN control as well, the wrapper file will be registered with ''svn add'' Be sure to eventually submit it into the repository together with the client!+If your extension is managed with source version control like gitremember to eventually commit all changes in the ''cpperl'' subdirectory.
  
 To debug a client, you must start the whole perl interpreter under gdb.  Before you do this for the first time, you should store two useful settings in ''~/.gdbinit'': To debug a client, you must start the whole perl interpreter under gdb.  Before you do this for the first time, you should store two useful settings in ''~/.gdbinit'':
Line 407: Line 407:
 Now you can start polymake as follows: Now you can start polymake as follows:
   gdb -args perl -S polymake   gdb -args perl -S polymake
-If you are debugging a client compiled in the SVN working copy of the polymake source tree, which is probably not contained in your PATH, then you should omit the option ''-S'' and specify the full path to ''/your/working/copy/perl/polymake'' instead.+If you are debugging a client compiled in the working copy of the polymake source tree, which is probably not contained in your PATH, then you should omit the option ''-S'' and specify the full path to ''/your/working/copy/perl/polymake'' instead.
  
-//Remark:// Up to polymake version 2.12, the environment variable was called ''POLYMAKE_DEBUG_CLIENTS'' Moreover, polymake took it into consideration only when a flag ''-d'' (increasing debug level) was specified on the command line.  This is not required anymore. 
-Up to polymake version 2.14, the environment variable was called ''POLYMAKE_CLIENT_SUFFIX''. 
  
 As soon as you see the ''(gdb)'' prompt, set a breakpoint in your client's code: As soon as you see the ''(gdb)'' prompt, set a breakpoint in your client's code:
Line 421: Line 419:
   (gdb) call M.dump()   (gdb) call M.dump()
 The output goes to ''stderr'', thus be sure not to redirect it (polymake never does it on its own). The output goes to ''stderr'', thus be sure not to redirect it (polymake never does it on its own).
 +
  • user_guide/extend/clients.txt
  • Last modified: 2021/06/17 06:43
  • by oberlaender