This appears to work as of Sage 7.3 only to a limited extent, for reasons that will be come clear. Start with a pure Python example to highlight the changes necessary to import Sage. A file hello.pyx with the simple code
print('Hello World!')
can be converted to C with the command
sage -cython --embed hello.pyx
and then compiled for running with the command
gcc hello.c -I/usr/include/python2.7 -lpython2.7
Executing the result by typing ./a.out
displays the expected greeting.
Now try a similar piece of code with a Sage numeric function in a file import.pyx:
from sage.all import *
print(bessel_J(0,1.))
Compiling with the same commands produces the reported error
ImportError: No module named sage.all
when executing the result. This error can be avoided by pointing the compiler to folders under Sage's location /path/to/sage/
so that it knows where to find Sage-specific libraries, including the version of Python that ships with Sage.
While the Cython command remains the same, the compiler command becomes
gcc import.pyx -I/path/to/sage/local/include/python2.7 -L/path/to/sage/local/lib -lpython2.7
The compiler program can now find the required module, but unfortunately another error appears upon execution:
RuntimeError: You must get the file local/bin/sage-maxima.lisp
Since that file gets installed with Sage, the source of this error is how Sage is written. The Maxima interface does an explicit check for this file when Sage starts, as can be seen in the source code, but this depends on having an environment variable set. This error can be avoided by entering
export SAGE_LOCAL=/path/to/sage/local
at the command line. Executing the compiled result now gives the output
? cannot open `standard.lib`
0.765197686558
which has the desired numeric output, but another error message. Since standard.lib is part of the Singular library, there is clearly another hard-coded path issue somewhere else in Sage.
Since the compiled program depends explicitly on setting an environment variable, it hardly qualifies as a stand-alone executable. Even worse, attempting to process symbolic manipulations as simple as
from sage.all import *
x=var('x')
print(x)
produces the C-related error
SystemError: NULL result without error in PyObject_Call
Looks like you can compile numeric parts of Sage to C to some extent, but for the symbolics would need to cythonize and compile everything.
I fear that, even if you succeed to achieve that, your binary will be huge.