Ticket #11680: trac_11680.patch

File trac_11680.patch, 8.5 KB (added by malb, 10 years ago)
  • doc/en/developer/coding_in_cython.rst

    # HG changeset patch
    # User wstein@gmail.com and martinralbrecht@googlemail.com
    # Date 1313994406 -3600
    # Node ID f4e5526645c7be17695aeeb47aef2ce3bb74fd5d
    # Parent  fb99d6d61fc79ca9ac8661c2727e1cbe58cc3627
    trac 11680: support cython extra_compile_args; made testing framework more thorough
    
    diff -r fb99d6d61fc7 -r f4e5526645c7 doc/en/developer/coding_in_cython.rst
    a b  
    104104* cinclude --- additional directories to search for header files. The
    105105  space separated list is split and passed to distutils.
    106106
     107* cfile -- additional C or C++ files to be compiled
     108
     109* cargs -- additional parameters passed to the compiler
     110
    107111For example::
    108112
    109113    #clang C++
    110114    #clib givaro
    111115    #cinclude /usr/local/include/
     116    #cargs -ggdb
     117    #cfile foo.c
    112118
    113119
    114120Attaching or loading .spyx files
  • sage/misc/cython.py

    diff -r fb99d6d61fc7 -r f4e5526645c7 sage/misc/cython.py
    a b  
    44AUTHORS:
    55    -- William Stein (2006-01-18): initial version
    66    -- William Stein (2007-07-28): update from sagex to cython
     7    -- Martin Albrecht & William Stein (2011-08): cfile & cargs
    78"""
    89
    910#*****************************************************************************
     
    121122    return environ_parse(s)
    122123
    123124def pyx_preparse(s):
    124     r"""
    125     Preparse a Pyx file
     125    """
     126    Preparse a pyx file
    126127      * include cdefs.pxi, interrupt.pxi, stdsage.pxi
    127128      * parse clang pragma (c or c++)
    128129      * parse clib pragma (additional libraries to link in)
    129130      * parse cinclude (additional include directories)
     131      * parse cfile (additional files to be included)
     132      * parse cargs (additional parameters passed to the compiler)
    130133
    131134    The pragmas:
    132     \begin{description}
    133       \item[clang] may be either c or c++ indicating whether a C or
    134                    C++ compiler should be used
    135135
    136       \item[clib] additional libraries to be linked in, the space
    137                   separated list is split and passed to distutils.
     136    - ``clang`` - may be either c or c++ indicating whether a C or C++
     137      compiler should be used
    138138
    139       \item[cinclude] additional directories to search for header
    140                       files. The space separated list is split and
    141                       passed to distutils.
    142     \end{description}
     139    - ``clib`` - additional libraries to be linked in, the space
     140      separated list is split and passed to distutils.
     141
     142    - ``cinclude`` - additional directories to search for header
     143      files. The space separated list is split and passed to
     144      distutils.
     145
     146    - ``cfile`` - additional C or C++ files to be compiled
     147      ('$SAGE_ROOT' is expanded, other environment variables are not.)
     148
     149    - ``cargs`` - additional parameters passed to the compiler
     150
     151    OUTPUT:
     152       preamble, libs, includes, language, files, args
    143153
    144154    EXAMPLE:
    145155        sage: from sage.misc.cython import pyx_preparse
     
    167177        '.../devel/sage/',
    168178        '.../devel/sage/sage/gsl/'],
    169179        'c',
    170         [])
    171         sage: s, libs, inc, lang, f = pyx_preparse("# clang c++\n #clib foo\n # cinclude bar\n")
     180        [], ['-w', '-O2'])
     181        sage: s, libs, inc, lang, f, args = pyx_preparse("# clang c++\n #clib foo\n # cinclude bar\n")
    172182        sage: lang
    173183        'c++'
    174184
     
    193203        '.../devel/sage/sage/ext/',
    194204        '.../devel/sage/',
    195205        '.../devel/sage/sage/gsl/']
     206
     207        sage: s, libs, inc, lang, f, args = pyx_preparse("# cargs -O3 -ggdb\n")
     208        sage: args
     209        ['-w', '-O2', '-O3', '-ggdb']
     210
     211    TESTS::
     212
     213        sage: module = sage.misc.cython.import_test("trac11680")
     214        sage: R.<x> = QQ[]
     215        sage: module.evaluate_at_power_of_gen(x^3 + x - 7, 5)
     216        x^15 + x^5 - 7
    196217    """
    197     lang = parse_keywords('clang', s)
    198     if lang[0]:
    199         lang = lang[0][0]
     218    lang, s = parse_keywords('clang', s)
     219    if lang:
     220        lang = lang[0]
    200221    else:
    201222        lang = "c"
    202223
     
    210231    s = """\ninclude "cdefs.pxi"\n""" + s
    211232    if lang != "c++": # has issues with init_csage()
    212233        s = """\ninclude "interrupt.pxi"  # ctrl-c interrupt block support\ninclude "stdsage.pxi"  # ctrl-c interrupt block support\n""" + s
    213     return s, libs, inc, lang, additional_source_files
     234    args, s = parse_keywords('cargs', s)
     235    args = ['-w','-O2'] + args
     236
     237    return s, libs, inc, lang, additional_source_files, args
    214238
    215239################################################################
    216240# If the user attaches a .spyx file and changes it, we have
     
    287311       
    288312    F = open(filename).read()
    289313
    290     F, libs, includes, language, additional_source_files = pyx_preparse(F)
     314    F, libs, includes, language, additional_source_files, extra_args = pyx_preparse(F)
    291315
    292316    # add the working directory to the includes so custom headers etc. work
    293317    includes.append(os.path.split(os.path.splitext(filename)[0])[0])
     
    308332        # increment the sequence number so will use a different one next time.
    309333        sequence_number[base] += 1
    310334
    311     additional_source_files = ",".join(["'"+os.path.abspath(os.curdir)+"/"+fname+"'" \
    312                                         for fname in additional_source_files])
    313    
     335    file_list = []
     336    for fname in additional_source_files:
     337        fname = fname.replace("$SAGE_ROOT",SAGE_ROOT)
     338        if fname.startswith(os.path.sep):
     339            file_list.append("'"+fname+"'")
     340        else:
     341            file_list.append("'"+os.path.abspath(os.curdir)+"/"+fname+"'")
     342    additional_source_files = ",".join(file_list)
     343
    314344    pyx = '%s/%s.pyx'%(build_dir, name)
    315345    open(pyx,'w').write(F)
    316346    setup="""
     
    326356    SAGE_LOCAL = SAGE_ROOT + '/local/'
    327357
    328358extra_link_args =  ['-L' + SAGE_LOCAL + '/lib']
    329 extra_compile_args = ['-w','-O2']
     359extra_compile_args = %s
    330360
    331361ext_modules = [Extension('%s', sources=['%s.%s', %s],
    332362                     libraries=%s,
     
    337367                     
    338368setup(ext_modules = ext_modules,
    339369      include_dirs = %s)
    340     """%(name, name, extension, additional_source_files, libs, language, includes)
     370    """%(extra_args, name, name, extension, additional_source_files, libs, language, includes)
    341371    open('%s/setup.py'%build_dir,'w').write(setup)
    342372
    343373    cython_include = ' '.join(["-I '%s'"%x for x in includes if len(x.strip()) > 0 ])
     
    571601    return s
    572602
    573603
     604def compile_and_load(code):
     605    """
     606    INPUT:
    574607
     608        - ``code`` -- string containing code that could be in a .pyx
     609          file that is attached or put in a %cython block in the
     610          notebook.
     611
     612    OUTPUT:
     613   
     614        - a module, which results from compiling the given code and
     615          importing it
     616
     617    EXAMPLES::
     618
     619        sage: module = sage.misc.cython.compile_and_load("def f(int n):\n    return n*n")
     620        sage: module.f(10)
     621        100
     622    """
     623    from sage.misc.misc import tmp_filename
     624    file = tmp_filename() + ".pyx"
     625    open(file,'w').write(code)
     626    from sage.server.support import cython_import
     627    return cython_import(file)
     628
     629
     630TESTS = {
     631'trac11680':"""
     632#cargs -std=c99 -O3 -ggdb
     633#cinclude $SAGE_ROOT/devel/sage/sage/libs/flint $SAGE_LOCAL/include/FLINT
     634#clib flint
     635#cfile $SAGE_ROOT/devel/sage/sage/libs/flint/fmpq_poly.c
     636
     637from sage.rings.rational cimport Rational
     638from sage.rings.polynomial.polynomial_rational_flint cimport Polynomial_rational_flint
     639from sage.libs.flint.fmpq_poly cimport (fmpq_poly_get_coeff_mpq, fmpq_poly_set_coeff_mpq,
     640                                        fmpq_poly_length)
     641
     642def evaluate_at_power_of_gen(Polynomial_rational_flint f, unsigned long n):
     643    assert n >= 1
     644    cdef Polynomial_rational_flint res = f._new()
     645    cdef unsigned long k
     646    cdef Rational z = Rational(0)
     647    for k in range(fmpq_poly_length(f.__poly)):
     648        fmpq_poly_get_coeff_mpq(z.value, f.__poly, k)
     649        fmpq_poly_set_coeff_mpq(res.__poly, n*k, z.value)
     650    return res
     651""",
     652
     653'trac11680b':"""
     654def f(int a, int b, int c):
     655    return a+b+c
     656"""
     657}
     658
     659def import_test(name):
     660    """
     661    This is used by the testing infrastructure to test building
     662    Cython programs.
     663
     664    INPUT:
     665        - ``name`` -- string; name of a key to the TESTS dictionary above
     666
     667    OUTPUT:
     668        - a module, which results from compiling the given code and importing it
     669
     670    EXAMPLES::
     671   
     672        sage: module = sage.misc.cython.import_test("trac11680b")
     673        sage: module.f(2,3,4)
     674        9
     675    """
     676    return compile_and_load(TESTS[name])
     677