Example #1
0
static bool analyze_program(const char* name, CompileJob& job)
{
    string compiler_name = find_basename( name );

    string::size_type pos = compiler_name.rfind('/');
    if (pos != string::npos)
        compiler_name = compiler_name.substr(pos);

    job.setCompilerName( compiler_name );

    string suffix = compiler_name;
    if ( compiler_name.size() > 2)
        suffix = compiler_name.substr(compiler_name.size()-2);

    if (suffix == "++" || suffix == "CC")
        job.setLanguage (CompileJob::Lang_CXX);
    else if (suffix == "cc")
        job.setLanguage (CompileJob::Lang_C);
    else if (compiler_name == "clang")
        job.setLanguage (CompileJob::Lang_C);
    else {
        job.setLanguage( CompileJob::Lang_Custom );
        job.setCompilerName( name ); // keep path
        return true;
    }

    return false;
}
Example #2
0
int main(int argc, char **argv)
{
    char *env = getenv("ICECC_DEBUG");
    int debug_level = Error;

    if (env) {
        if (!strcasecmp(env, "info"))  {
            debug_level |= Info | Warning;
        } else if (!strcasecmp(env, "warnings")) {
            debug_level |= Warning; // taking out warning
        } else { // any other value
            debug_level |= Info | Debug | Warning;
        }
    }

    std::string logfile;

    if (const char *logfileEnv = getenv("ICECC_LOGFILE")) {
        logfile = logfileEnv;
    }

    setup_debug(debug_level, logfile, "ICECC");

    CompileJob job;
    bool icerun = false;

    string compiler_name = argv[0];
    dcc_client_catch_signals();

    char cwd[ PATH_MAX ];
    if( getcwd( cwd, PATH_MAX ) != NULL )
        job.setWorkingDirectory( cwd );

    if (find_basename(compiler_name) == rs_program_name) {
        if (argc > 1) {
            string arg = argv[1];

            if (arg == "--help") {
                dcc_show_usage();
                return 0;
            }

            if (arg == "--version") {
                printf("ICECC " VERSION "\n");
                return 0;
            }

            if (arg == "--build-native") {
                return create_native(argv + 2);
            }

            if (arg.size() > 0) {
                job.setCompilerName(arg);
                job.setCompilerPathname(arg);
            }
        }
    } else if (find_basename(compiler_name) == "icerun") {
        icerun = true;

        if (argc > 1) {
            string arg = argv[1];

            if (arg == "--help") {
                icerun_show_usage();
                return 0;
            }

            if (arg == "--version") {
                printf("ICERUN " VERSION "\n");
                return 0;
            }

            if (arg.size() > 0) {
                job.setCompilerName(arg);
                job.setCompilerPathname(arg);
            }
        }
    } else {
        std::string resolved;

        // check if it's a symlink to icerun
        if (resolve_link(compiler_name, resolved) == 0 && find_basename(resolved) == "icerun") {
            icerun = true;
        }
    }

    int sg_level = dcc_recursion_safeguard();

    if (sg_level > 0) {
        log_error() << "icecream seems to have invoked itself recursively!" << endl;
        return EXIT_RECURSION;
    }

    /* Ignore SIGPIPE; we consistently check error codes and will
     * see the EPIPE. */
    dcc_ignore_sigpipe(1);

    list<string> extrafiles;
    local |= analyse_argv(argv, job, icerun, &extrafiles);

    /* If ICECC is set to disable, then run job locally, without contacting
       the daemon at all. Because of file-based locking that is used in this
       case, all calls will be serialized and run by one.
       If ICECC is set to no, the job is run locally as well, but it is
       serialized using the daemon, so several may be run at once.
     */
    char *icecc = getenv("ICECC");

    if (icecc && !strcasecmp(icecc, "disable")) {
        return build_local(job, 0);
    }

    if (icecc && !strcasecmp(icecc, "no")) {
        local = true;
    }

    if (const char *extrafilesenv = getenv("ICECC_EXTRAFILES")) {
        for (;;) {
            const char *colon = strchr(extrafilesenv, ':');
            string file;

            if (colon == NULL) {
                file = extrafilesenv;
            } else {
                file = string(extrafilesenv, colon - extrafilesenv);
            }

            file = get_absfilename(file);

            struct stat st;
            if (stat(file.c_str(), &st) == 0) {
                extrafiles.push_back(file);
            } else {
                log_warning() << "File in ICECC_EXTRAFILES not found: " << file << endl;
                return build_local(job, 0);
            }

            if (colon == NULL) {
                break;
            }

            extrafilesenv = colon + 1;
        }
    }

    MsgChannel *local_daemon;
    if (getenv("ICECC_TEST_SOCKET") == NULL) {
        /* try several options to reach the local daemon - 3 sockets, one TCP */
        local_daemon = Service::createChannel("/var/run/icecc/iceccd.socket");

        if (!local_daemon) {
            local_daemon = Service::createChannel("/var/run/iceccd.socket");
        }

        if (!local_daemon && getenv("HOME")) {
            string path = getenv("HOME");
            path += "/.iceccd.socket";
            local_daemon = Service::createChannel(path);
        }

        if (!local_daemon) {
            local_daemon = Service::createChannel("127.0.0.1", 10245, 0/*timeout*/);
        }
    } else {
        local_daemon = Service::createChannel(getenv("ICECC_TEST_SOCKET"));
        if (!local_daemon) {
            log_error() << "test socket error" << endl;
            return EXIT_TEST_SOCKET_ERROR;
        }
    }

    if (!local_daemon) {
        log_warning() << "no local daemon found" << endl;
        return build_local(job, 0);
    }

    Environments envs;

    if (!local) {
        if (getenv("ICECC_VERSION")) {     // if set, use it, otherwise take default
            try {
                envs = parse_icecc_version(job.targetPlatform(), find_prefix(job.compilerName()));
            } catch (int x) {
                // we just build locally
            }
        } else if (!extrafiles.empty() && !IS_PROTOCOL_32(local_daemon)) {
            log_warning() << "Local daemon is too old to handle compiler plugins." << endl;
            local = true;
        } else {
            if (!local_daemon->send_msg(GetNativeEnvMsg(compiler_is_clang(job)
                                        ? "clang" : "gcc", extrafiles))) {
                log_warning() << "failed to write get native environment" << endl;
                goto do_local_error;
            }

            // the timeout is high because it creates the native version
            Msg *umsg = local_daemon->get_msg(4 * 60);
            string native;

            if (umsg && umsg->type == M_NATIVE_ENV) {
                native = static_cast<UseNativeEnvMsg*>(umsg)->nativeVersion;
            }

            if (native.empty() || ::access(native.c_str(), R_OK)) {
                log_warning() << "daemon can't determine native environment. "
                              "Set $ICECC_VERSION to an icecc environment.\n";
            } else {
                envs.push_back(make_pair(job.targetPlatform(), native));
                log_info() << "native " << native << endl;
            }

            delete umsg;
        }

        // we set it to local so we tell the local daemon about it - avoiding file locking
        if (envs.size() == 0) {
            local = true;
        }

        for (Environments::const_iterator it = envs.begin(); it != envs.end(); ++it) {
            trace() << "env: " << it->first << " '" << it->second << "'" << endl;

            if (::access(it->second.c_str(), R_OK)) {
                log_error() << "can't read environment " << it->second << endl;
                local = true;
            }
        }
    }

    int ret;

    if (local) {
        log_block b("building_local");
        struct rusage ru;
        Msg *startme = 0L;

        /* Inform the daemon that we like to start a job.  */
        if (local_daemon->send_msg(JobLocalBeginMsg(0, get_absfilename(job.outputFile())))) {
            /* Now wait until the daemon gives us the start signal.  40 minutes
               should be enough for all normal compile or link jobs.  */
            startme = local_daemon->get_msg(40 * 60);
        }

        /* If we can't talk to the daemon anymore we need to fall back
           to lock file locking.  */
        if (!startme || startme->type != M_JOB_LOCAL_BEGIN) {
            goto do_local_error;
        }

        ret = build_local(job, local_daemon, &ru);
    } else {
        try {
            // check if it should be compiled three times
            const char *s = getenv("ICECC_REPEAT_RATE");
            int rate = s ? atoi(s) : 0;
            ret = build_remote(job, local_daemon, envs, rate);

            /* We have to tell the local daemon that everything is fine and
               that the remote daemon will send the scheduler our done msg.
               If we don't, the local daemon will have to assume the job failed
               and tell the scheduler - and that fail message may arrive earlier
               than the remote daemon's success msg. */
            if (ret == 0) {
                local_daemon->send_msg(EndMsg());
            }
        } catch (int error) {
            if (error >= 100) {
                log_info() << "local build forced by error " << error << endl;
                goto do_local_error;
            }
            if (remote_daemon.size()) {
                log_error() << "got exception " << error
                            << " (" << remote_daemon.c_str() << ") " << endl;
            } else {
                log_error() << "got exception " << error << " (this should be an exception!)" <<
                            endl;
            }

            /* currently debugging a client? throw an error then */
            if (debug_level != Error) {
                return error;
            }

            goto do_local_error;
        }
    }

    delete local_daemon;
    return ret;

do_local_error:
    delete local_daemon;
    return build_local(job, 0);
}