CFCPerl* CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const char *lib_dir, const char *boot_class, const char *header, const char *footer) { CFCUTIL_NULL_CHECK(hierarchy); CFCUTIL_NULL_CHECK(lib_dir); CFCUTIL_NULL_CHECK(boot_class); CFCUTIL_NULL_CHECK(header); CFCUTIL_NULL_CHECK(footer); self->hierarchy = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy); self->lib_dir = CFCUtil_strdup(lib_dir); self->boot_class = CFCUtil_strdup(boot_class); self->header = CFCUtil_strdup(header); self->footer = CFCUtil_strdup(footer); // Derive path to generated .xs file. self->xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", lib_dir, boot_class); S_replace_double_colons(self->xs_path, CHY_DIR_SEP_CHAR); // Derive the name of the bootstrap function. self->boot_func = CFCUtil_sprintf("cfish_%s_bootstrap", boot_class); for (int i = 0; self->boot_func[i] != 0; i++) { if (!isalnum(self->boot_func[i])) { self->boot_func[i] = '_'; } } return self; }
static CFCPerlPodFile* S_write_class_pod(CFCPerl *self) { CFCPerlClass **registry = CFCPerlClass_registry(); size_t num_registered = 0; while (registry[num_registered] != NULL) { num_registered++; } CFCPerlPodFile *pod_files = (CFCPerlPodFile*)CALLOCATE(num_registered + 1, sizeof(CFCPerlPodFile)); size_t count = 0; // Generate POD, but don't write. That way, if there's an error while // generating pod, we leak memory but don't clutter up the file system. for (size_t i = 0; i < num_registered; i++) { const char *class_name = CFCPerlClass_get_class_name(registry[i]); char *raw_pod = CFCPerlClass_create_pod(registry[i]); if (!raw_pod) { continue; } char *pod = CFCUtil_sprintf("%s\n%s%s", self->pod_header, raw_pod, self->pod_footer); char *pod_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.pod", self->lib_dir, class_name); S_replace_double_colons(pod_path, CHY_DIR_SEP_CHAR); pod_files[count].contents = pod; pod_files[count].path = pod_path; count++; FREEMEM(raw_pod); } pod_files[count].contents = NULL; pod_files[count].path = NULL; return pod_files; }
static void S_write_boot_h(CFCPerl *self) { char *guard = CFCUtil_sprintf("%s_BOOT", self->boot_class); S_replace_double_colons(guard, '_'); for (char *ptr = guard; *ptr != '\0'; ptr++) { if (isalpha(*ptr)) { *ptr = toupper(*ptr); } } const char pattern[] = "%s\n" "\n" "#ifndef %s\n" "#define %s 1\n" "\n" "void\n" "%s();\n" "\n" "#endif /* %s */\n" "\n" "%s\n"; char *content = CFCUtil_sprintf(pattern, self->header, guard, guard, self->boot_func, guard, self->footer); const char *inc_dest = CFCHierarchy_get_include_dest(self->hierarchy); char *boot_h_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "boot.h", inc_dest); CFCUtil_write_file(boot_h_path, content, strlen(content)); FREEMEM(boot_h_path); FREEMEM(content); FREEMEM(guard); }
void CFCPerl_write_bindings(CFCPerl *self, const char *boot_class, CFCParcel **parcels) { CFCUTIL_NULL_CHECK(boot_class); CFCUTIL_NULL_CHECK(parcels); CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); CFCPerlClass **registry = CFCPerlClass_registry(); char *privacy_syms = CFCUtil_strdup(""); char *includes = CFCUtil_strdup(""); char *generated_xs = CFCUtil_strdup(""); char *class_specs = CFCUtil_strdup(""); char *xsub_specs = CFCUtil_strdup(""); char *bootstrap_calls = CFCUtil_strdup(""); char *hand_rolled_xs = CFCUtil_strdup(""); for (size_t i = 0; parcels[i]; ++i) { CFCParcel *parcel = parcels[i]; // Set host_module_name for parcel. if (!CFCParcel_included(parcel) && CFCParcel_is_installed(parcel)) { CFCParcel_set_host_module_name(parcel, boot_class); } // Bake the parcel privacy defines into the XS, so it can be compiled // without any extra compiler flags. const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); privacy_syms = CFCUtil_cat(privacy_syms, "#define ", privacy_sym, "\n", NULL); // Bootstrap calls. const char *prefix = CFCParcel_get_prefix(parcel); includes = CFCUtil_cat(includes, "#include \"", prefix, "perl.h\"\n", NULL); bootstrap_calls = CFCUtil_cat(bootstrap_calls, " ", prefix, "bootstrap_perl();\n", NULL); } for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; CFCParcel *parcel = CFCClass_get_parcel(klass); int found = false; for (size_t j = 0; parcels[j]; j++) { if (parcel == parcels[j]) { found = true; break; } } if (!found) { continue; } // Pound-includes for generated headers. const char *include_h = CFCClass_include_h(klass); includes = CFCUtil_cat(includes, "#include \"", include_h, "\"\n", NULL); if (CFCClass_inert(klass)) { continue; } int num_xsubs = 0; // Constructors. CFCPerlConstructor **constructors = CFCPerlClass_constructor_bindings(klass); for (size_t j = 0; constructors[j] != NULL; j++) { CFCPerlSub *xsub = (CFCPerlSub*)constructors[j]; // Add the XSUB function definition. char *xsub_def = CFCPerlConstructor_xsub_def(constructors[j], klass); generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n", NULL); FREEMEM(xsub_def); // Add XSUB initialization at boot. xsub_specs = S_add_xsub_spec(xsub_specs, xsub); num_xsubs += 1; CFCBase_decref((CFCBase*)constructors[j]); } FREEMEM(constructors); // Methods. CFCPerlMethod **methods = CFCPerlClass_method_bindings(klass); for (size_t j = 0; methods[j] != NULL; j++) { CFCPerlSub *xsub = (CFCPerlSub*)methods[j]; // Add the XSUB function definition. char *xsub_def = CFCPerlMethod_xsub_def(methods[j], klass); generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n", NULL); FREEMEM(xsub_def); // Add XSUB initialization at boot. xsub_specs = S_add_xsub_spec(xsub_specs, xsub); num_xsubs += 1; CFCBase_decref((CFCBase*)methods[j]); } FREEMEM(methods); // Append XSBind_ClassSpec entry. const char *class_name = CFCClass_get_name(klass); CFCClass *parent = CFCClass_get_parent(klass); char *parent_name; if (parent) { parent_name = CFCUtil_sprintf("\"%s\"", CFCClass_get_name(parent)); } else { parent_name = CFCUtil_strdup("NULL"); } char *class_spec = CFCUtil_sprintf("{ \"%s\", %s, %d }", class_name, parent_name, num_xsubs); const char *sep = class_specs[0] == '\0' ? "" : ",\n"; class_specs = CFCUtil_cat(class_specs, sep, " ", class_spec, NULL); FREEMEM(class_spec); FREEMEM(parent_name); } // Hand-rolled XS. for (size_t i = 0; registry[i] != NULL; i++) { CFCPerlClass *perl_class = registry[i]; CFCParcel *parcel = CFCPerlClass_get_parcel(perl_class); int found = false; for (size_t j = 0; parcels[j]; j++) { if (parcel == parcels[j]) { found = true; break; } } if (!found) { continue; } const char *xs = CFCPerlClass_get_xs_code(perl_class); hand_rolled_xs = CFCUtil_cat(hand_rolled_xs, xs, "\n", NULL); } const char pattern[] = "%s" // Header. "\n" "%s" // Privacy syms. "\n" "#include \"XSBind.h\"\n" "%s" // Includes. "\n" "#ifndef XS_INTERNAL\n" " #define XS_INTERNAL XS\n" "#endif\n" "\n" "%s" // Generated XS. "\n" "MODULE = %s PACKAGE = %s\n" // Boot class. "\n" "BOOT:\n" "{\n" " static const cfish_XSBind_ClassSpec class_specs[] = {\n" "%s\n" // Class specs. " };\n" " static const cfish_XSBind_XSubSpec xsub_specs[] = {\n" "%s\n" // XSUB specs. " };\n" " size_t num_classes\n" " = sizeof(class_specs) / sizeof(class_specs[0]);\n" " const char* file = __FILE__;\n" "\n" "%s" // Bootstrap calls. "\n" " cfish_XSBind_bootstrap(aTHX_ num_classes, class_specs,\n" " xsub_specs, file);\n" "}\n" "\n" "%s" // Hand-rolled XS. "\n" "%s"; // Footer char *contents = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes, generated_xs, boot_class, boot_class, class_specs, xsub_specs, bootstrap_calls, hand_rolled_xs, self->c_footer); // Derive path to generated .xs file. char *xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", self->lib_dir, boot_class); S_replace_double_colons(xs_path, CHY_DIR_SEP_CHAR); // Write out if there have been any changes. CFCUtil_write_if_changed(xs_path, contents, strlen(contents)); FREEMEM(xs_path); FREEMEM(contents); FREEMEM(hand_rolled_xs); FREEMEM(bootstrap_calls); FREEMEM(xsub_specs); FREEMEM(class_specs); FREEMEM(generated_xs); FREEMEM(includes); FREEMEM(privacy_syms); FREEMEM(ordered); }