in reply to XS from XS?

I know of two ways to do it.

First, you can go through the Perl interface using the callback API from perlcall. That would definitely not qualify as "easy", though.

Alternatively, you can get the source library to export its C functions somehow. There are numerous ways to accomplish this, some of which are discussed in Dynaloader/XS: sharing C symbols across shared objects. Cross-platform exporting is difficult. I ultimately adopted the technique from Time::HiRes described by salva.

Here's code from Snowball.xs which makes 4 symbols from the Snowball stemming library available (sb_stemmer_list, etc):

MODULE = Lingua::Stem::Snowball PACKAGE = Lingua::Stem::Snowball PROTOTYPES: disable BOOT: { SV *sb_stemmer_list_sv = newSViv(PTR2IV(sb_stemmer_list)); SV *sb_stemmer_new_sv = newSViv(PTR2IV(sb_stemmer_new)); SV *sb_stemmer_delete_sv = newSViv(PTR2IV(sb_stemmer_delete)); SV *sb_stemmer_stem_sv = newSViv(PTR2IV(sb_stemmer_stem)); SV *sb_stemmer_length_sv = newSViv(PTR2IV(sb_stemmer_length)); hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_list", +39, sb_stemmer_list_sv, 0); hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_new", 3 +8, sb_stemmer_new_sv, 0); hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_delete" +, 41, sb_stemmer_delete_sv, 0); hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_stem", +39, sb_stemmer_stem_sv, 0); hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_length" +, 41, sb_stemmer_length_sv, 0); }

That works for a small list of functions. It would be cumbersome and impractical for a large export list.