'\" '\" Generated from file 'critcl_usingit\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) Jean-Claude Wippler '\" Copyright (c) Steve Landers '\" Copyright (c) 2011-2018 Andreas Kupries '\" .TH "critcl_use" 3tcl 3\&.1\&.18\&.1 doc "C Runtime In Tcl (CriTcl)" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME critcl_use \- Using Critcl .SH DESCRIPTION .PP \fIC Runtime In Tcl\fR, or \fICriTcl\fR , is a system for compiling C code embedded in Tcl on the fly and either loading the resulting objects into Tcl for immediate use or packaging them for distribution\&. Use \fICriTcl\fR to improve performance by rewriting in C those routines that are performance bottlenecks\&. .PP This document is a (hopefully) gentle introduction to Critcl by way of a series of small examples\&. .PP Readers which came directly to this document through a search or similar, and are thus in need of an overview of the whole system, are advised to read the \fIIntroduction To CriTcl\fR first\&. .PP The examples here cover both how to embed C into Tcl with it, and how to build the distributable packages\&. As such the intended audience are both writers of packages with embedded C, and people building such packages\&. To make things easier the two themes each have their own section in this document, enabling all readers to quickly skip the part they are not interested in\&. .PP The sources of Critcl, should you have gotten them, contain several larger examples show-casing various aspects of the system\&. These demonstration packages can all be found in the sub-directory "\fIexamples/\fR" of the sources\&. .SH "EMBEDDING C" This is the section for developers writing, or wishing to write, a package embedding C into Tcl via critcl\&. .PP I guess that we are allowed to asssume that you, gentle reader, are here because you have written some Tcl code which is not fast enough (any more) and you wish to make it "go faster" by replacing parts (or all) of it with speedy C\&. .PP Another, and I believe reasonable assumption to make would be that you have already investigated and ruled out or done things like changes to data structures and algorithms which reduce O(n*n) work to O (n*log n), O(n), or even O(1)\&. Of course, nothing prevents you from forging ahead here even if you have not done such\&. Still, even in that case I would recommend that you consider investigating this line of making your code go faster as well\&. .PP Now, with these introductory words out of the way, lets jump into the meat of things\&. .SS "A SIMPLE PROCEDURE" Starting simple, let us assume that the Tcl code in question is something like .CS proc math {x y z} { return [expr {(sin($x)*rand())/$y**log($z)}] } .CE with the expression pretending to be something very complex and slow\&. Converting this to C we get: .CS critcl::cproc math {double x double y double z} double { double up = rand () * sin (x); double down = pow(y, log (z)); return up/down; } .CE Notable about this translation: .IP [1] All the arguments got type information added to them, here "double"\&. Like in C the type precedes the argument name\&. Other than that it is pretty much a Tcl dictionary, with keys and values swapped\&. .IP [2] We now also have to declare the type of the result, here "double", again\&. .IP [3] The reference manpage lists all the legal C types supported as arguments and results\&. .PP .SS "CUSTOM TYPES, INTRODUCTION" When writing bindings to external libraries \fBcritcl::cproc\fR is usually the most convenient way of writing the lower layers\&. This is however hampered by the fact that critcl on its own only supports a few standard (arguably the most import) standard types, whereas the functions we wish to bind most certainly will use much more, specific to the library's function\&. .PP The critcl commands \fBargtype\fR, \fBresulttype\fR and their adjuncts are provided to help here, by allowing a developer to extend critcl's type system with custom conversions\&. .PP This and the three following sections will demonstrate this, from trivial to complex\&. .PP The most trivial use is to create types which are aliases of existing types, standard or other\&. As an alias it simply copies and uses the conversion code from the referenced types\&. .PP Our example is pulled from an incomplete project of mine, a binding to \fIJeffrey Kegler\fR's \fIlibmarpa\fR library managing Earley parsers\&. Several custom types simply reflect the typedef's done by the library, to make the \fBcritcl::cproc\fRs as self-documenting as the underlying library functions themselves\&. .CS critcl::argtype Marpa_Symbol_ID = int critcl::argtype Marpa_Rule_ID = int critcl::argtype Marpa_Rule_Int = int critcl::argtype Marpa_Rank = int critcl::argtype Marpa_Earleme = int critcl::argtype Marpa_Earley_Set_ID = int \&.\&.\&. method sym-rank: proc { Marpa_Symbol_ID sym Marpa_Rank rank } Marpa_Rank { return marpa_g_symbol_rank_set (instance->grammar, sym, rank); } \&.\&.\&. .CE .SS "CUSTOM TYPES, SEMI-TRIVIAL" A more involved custom argument type would be to map from Tcl strings to some internal representation, like an integer code\&. .PP The first example is taken from the \fBtclyaml\fR package, a binding to the \fBlibyaml\fR library\&. In a few places we have to map readable names for block styles, scalar styles, etc\&. to the internal enumeration\&. .CS critcl::argtype yaml_sequence_style_t { if (!encode_sequence_style (interp, @@, &@A)) return TCL_ERROR; } \&.\&.\&. critcl::ccode { static const char* ty_block_style_names [] = { "any", "block", "flow", NULL }; static int encode_sequence_style (Tcl_Interp* interp, Tcl_Obj* style, yaml_sequence_style_t* estyle) { int value; if (Tcl_GetIndexFromObj (interp, style, ty_block_style_names, "sequence style", 0, &value) != TCL_OK) { return 0; } *estyle = value; return 1; } } \&.\&.\&. method sequence_start proc { pstring anchor pstring tag int implicit yaml_sequence_style_t style } ok { /* Syntax: seq_start