Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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);
}