Rtcl is a Tcl extension for executing code in the R [L1 ] programming language. R is a free version of Bell Labs' S language for statistical computing. Rtcl embeds an R interpreter into Tcl, and allows access to it via Tcl commands. The latest version of Rtcl is available from


Rtcl was originally written by Neil McKay. His last published version is available from


Installation on macOS

TR Rtcl compiles and installs perfectly on macOS. The current version 1.2.2 also runs without the tweak described below (tested on macOS 13.5.2 Ventura running on an M1 machine).

  Installing Rtcl 1.2.1 on macOS (10.15.7 – Catalina)

I have successfully compiled and used the package on macOS Catalina (10.15.7), using Rtcl version 1.2.1. R version 4.0.4 is installed and lives under /Library/Frameworks/R.framework/Resources. This is the directory returned by


Compiling Rtcl using just with ./configure; make; make install works. However, I am getting the error message cannot load libR from the Rtcl package when I do package require Rtcl. This is because Rtcl cannot find the installed R. First, the R_HOME environment variable is not set by R, so the initialization script in Rtcl cannot use it. Second, the paths to R hard-coded into Rtcl do not match my installation, so Rtcl cannot find R at that place either. It doesn't help much to add the correct path in Rtcl's init code. This will help loading the library in Tcl but then R fails with saying cannot find system Renviron. It turns out that the easy solution is to just define the R_HOME environment variable and set it to the output of R RHOME. Depending on your setup, you can just put it into your profile:

    export R_HOME=`R RHOME`

You could also include it into the pkgIndex.tcl file of Rtcl, before the actual libRtcl1.2.1.dylib library is loaded, e.g.:

    set env(R_HOME) [exec /usr/local/bin/R RHOME]
    package ifneeded Rtcl 1.2.1 \
        [list load [file join $dir libRtcl1.2.1.dylib] Rtcl]


The package provides four new commands in the rtcl namespace:

    ::rtcl::eval ?-verbose? R Expression(s)
    ::rtcl::source ?-verbose? foo.R
    ::rtcl::gettype ?-verbose? R Expression(s)
    ::rtcl::getvalue ?-verbose? R Expression(s)

Here's an example output from the console:

% package require Rtcl
% # the following will just execute some R code without returning anything:
% ::rtcl::eval "a <- c(1:10)"
% # if you want to see the content of 'a', you need:
% ::rtcl::getvalue a
1 2 3 4 5 6 7 8 9 10
% # getvalue does also execute the command, so you can do both in one step:
% ::rtcl::getvalue "a <- c(1:10)"
1 2 3 4 5 6 7 8 9 10
% # loading R libraries works as usual:
% ::rtcl::eval library(sf)
% we can transfer data to R and get results back like this:
% set x 5
% set result [::rtcl::getvalue "$x * $x"]
% 25.0
% puts $result
% note, that Rtcl returned a 'real' value:
% ::rtcl::gettype "$x * $x"
% ... when doing this in plain R, you will get "25" and 'class(5*5)' will return only 'numeric', so 'real' is the safe choice ...

Another example with more complex data, using the built-in dataset 'mtcars':

package require Rtcl
% rtcl::eval {data(mtcars)}
% set l [rtcl::getvalue {head(mtcars, 6)}]
{21.0 21.0 22.8 21.4 18.7 18.1} {6.0 6.0 4.0 6.0 8.0 6.0} {160.0 160.0 108.0 258.0 360.0 225.0} {110.0 110.0 93.0 110.0 175.0 105.0} {3.9 3.9 3.85 3.08 3.15 2.76} {2.62 2.875 2.32 3.215 3.44 3.46} {16.46 17.02 18.61 19.44 17.02 20.22} {0.0 0.0 1.0 1.0 0.0 1.0} {1.0 1.0 1.0 0.0 0.0 0.0} {4.0 4.0 4.0 3.0 3.0 3.0} {4.0 4.0 1.0 1.0 2.0 1.0}
% llength $l
% lindex $l 1 2
% rtcl::getvalue {row.names(mtcars)}
{Mazda RX4} {Mazda RX4 Wag} {Datsun 710} {Hornet 4 Drive} {Hornet Sportabout} Valiant {Duster 360} {Merc 240D} {Merc 230} {Merc 280} {Merc 280C} {Merc 450SE} {Merc 450SL} {Merc 450SLC} {Cadillac Fleetwood} {Lincoln Continental} {Chrysler Imperial} {Fiat 128} {Honda Civic} {Toyota Corolla} {Toyota Corona} {Dodge Challenger} {AMC Javelin} {Camaro Z28} {Pontiac Firebird} {Fiat X1-9} {Porsche 914-2} {Lotus Europa} {Ford Pantera L} {Ferrari Dino} {Maserati Bora} {Volvo 142E}

This dataset 'mtcars' is an R "data.frame". As you can see, it is returned as a nested list with each element of the list being one column of the dataset. That is why llength $l doesn't return 6 (but 11 as the number of columns) when we asked for the first 6 rows. The column headers and row names are not included in the return value. If you need these you can get the column names using rtcl::getvalue {names(mtcars)}.