我正在尝试使用Make在OS X上编译C程序,但收到错误消息。

C代码

#define _XOPEN_SOURCE // required for cuserid to work

// includes
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <time.h>

// user-defined constants
#define FIB_MAX_ITERS 20
#define SLEEP_LENGTH 2

// Prints an error message and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val)
{
    if (syscall_val < 0) {
        perror("fork");
        exit(errno);
    } else {
        // No syscall error; we can return.
        return syscall_val;
    }
}

char* cuserid_wrapper()
{
    char* val = cuserid(NULL);
    if (val == NULL) {
        perror("cuserid");
        exit(errno);
    } else {
        return val;
    }
}

time_t time_wrapper()
{
    time_t val = time(NULL);
    if (val == ((time_t) -1)) {
        perror("time_wrapper");
        exit(errno);
    } else {
        return val;
    }
}

void getrusage_wrapper(struct rusage* output)
{
    int val = getrusage(RUSAGE_SELF, output);
    if (val == -1){
        perror("getrusage_wrapper");
        exit(errno);
    }
}

void print_uids_gids(const char* proc_name)
{
    printf("[%s] username: %s\n", proc_name, cuserid_wrapper());

    // According to man pages, following syscalls always succeed.
    // Hence, no error checking
    printf("[%s] user id: %d\n",  proc_name, getuid());
    printf("[%s] effective user id: %d\n", proc_name, geteuid());
    printf("[%s] group id: %d\n",  proc_name, getgid());
    printf("[%s] effective group id: %d\n", proc_name, getegid());
    printf("[%s] pid: %d\n", proc_name, getpid());
}

void print_exec_times(const char* proc_name)
{
    // build up some cpu time
    int k = 0;
    int i;
    for (i = 0; i < 100000000; i++) {
        k += 2;
    }

    time_t cur_time;
    struct rusage res_usage;

    cur_time = time_wrapper();
    getrusage_wrapper(&res_usage);

    printf("[%s] seconds since epoch: %d\n", proc_name, (int)cur_time);
    printf("[%s] current time: %s", proc_name, ctime(&cur_time));
    printf("[%s] user CPU time: %d us\n", proc_name, (int)res_usage.ru_utime.tv_usec);
    printf("[%s] system CPU time: %d us\n", proc_name, (int)res_usage.ru_stime.tv_usec);
}

void sleep_wrapper(unsigned int length)
{
    int time_left = length;
    while (time_left > 0) {
        time_left = sleep(length);
    }
}

char* getcwd_wrapper()
{
    char* cwd = getcwd(NULL, 0);
    if (cwd == NULL) {
        perror("getcwd_wrapper");
        exit(errno);
    } else {
        return cwd;
    }
}

void waitpid_wrapper(pid_t pid)
{
    int status;
    int val = waitpid(pid, &status, 0);
    if (val == -1) {
        perror("waitpid_wrapper");
        exit(errno);
    }
}

void child_proc(int fib_start, const char* proc_name)
{
    print_uids_gids(proc_name);
    // No errors can occur for getppid
    printf("[%s] parent PID: %d\n", proc_name, getppid());

    sleep(SLEEP_LENGTH); // sleep to align fibonacci prints
    // main loop - printing fibonacci numbers
    int f_prev = 1; // starts at f_1
    int f_cur = 1; // starts at f_2
    int f_cur_new;
    int f_prev_new;
    int i;
    for (i = fib_start; i <= FIB_MAX_ITERS; i += 2) { // want <= b/c 1-based index
        if (i % 2 == 1) {
            printf("[%s] f_%d = %d\n", proc_name, i, f_prev);
        } else if (i % 2 == 0) {
            printf("[%s] f_%d = %d\n", proc_name, i, f_cur);
        }

        f_cur_new  =  2 * f_cur + f_prev;
        f_prev_new = f_cur + f_prev;
        f_cur  = f_cur_new;
        f_prev = f_prev_new;

        sleep(SLEEP_LENGTH);
    }

    print_exec_times(proc_name);
    exit(0);
}

char* get_proc_name(const char* base, char* buff)
{
    sprintf(buff, "%s, PID=%d", base, (int)getpid());
    return (char*)buff;
}

int main(void)
{
    char parent_proc_name[255];
    get_proc_name("parent", parent_proc_name);
    // TODO: Error check the syscalls!
    printf("[%s] current working directory: %s\n",  parent_proc_name, getcwd_wrapper());
    print_uids_gids(parent_proc_name);

    pid_t child1_pid = print_if_err(fork());
    if (child1_pid == 0) {
        sleep(SLEEP_LENGTH / 2);

        char proc_name[255];
        get_proc_name("child1", proc_name);
        child_proc(1, proc_name);
    }
    printf("[%s] child1_pid: %d\n", parent_proc_name, child1_pid);

    pid_t child2_pid = print_if_err(fork());
    if (child2_pid == 0) {
        sleep(SLEEP_LENGTH);

        char proc_name[255];
        get_proc_name("child2", proc_name);
        child_proc(2, proc_name);
    }
    printf("[%s] child2_pid: %d\n", parent_proc_name, child1_pid);

    int status;
    // TODO: Error check the syscalls!
    waitpid(child1_pid, &status, 0);
    printf("[%s] child1 terminated\n", parent_proc_name);
    waitpid(child2_pid, &status, 0);
    printf("[%s] child2 terminated\n", parent_proc_name);
    print_exec_times(parent_proc_name);
    return 0;
}


制作文件

CC = gcc
C_FLAGS = -Wall -Wextra

all: eecs338_hw01

eecs338_hw01: eecs338_hw01.o
    $(CC) eecs338_hw01.o -o eecs338_hw01

eecs338_hw01.o: eecs338_hw01.c
    $(CC) -c $(C_FLAGS) eecs338_hw01.c

clean:
    rm -f eecs338_hw01 eecs338_hw01.o


错误

gcc eecs338_hw01.o -o eecs338_hw01
Undefined symbols for architecture x86_64:
  "_cuserid", referenced from:
      _cuserid_wrapper in eecs338_hw01.o
     (maybe you meant: _cuserid_wrapper)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [eecs338_hw01] Error 1

最佳答案

您应该设置#define _XOPEN_SOURCE 700(或600),而不仅仅是定义它。但是,这不应该影响链接,仅影响符号是否在标题中可见。

在Mac OS X上运行man cuserid会显示该功能没有手册页。

使用我的常规选项编译代码:

 gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
     -Wold-style-definition -Werror cuserid.c -o cuserid


要求我对您的代码进行一些小的更改。这些函数由static制成,因此不需要单独的原型,并且函数定义使用显式的void表示没有参数:

char* cuserid_wrapper(void)


代替:

char* cuserid_wrapper()


这些是相对较小的问题(当您不使用如此严格的编译选项进行开发时,或多或少是正常的)。完成这些更改后,我被告知sleep_wrapper()waitpid_wrapper()已定义但未使用(再次证明这不是MCVE)。我也得到:

cuserid.c:33:17: error: implicit declaration of function 'cuserid' [-Werror=implicit-function-declaration].


因此,链接失败并不奇怪。系统不知道cuserid()函数。我发现cuserid()当前不是POSIX的一部分。 cuserid()的Linux手册页说明:


  系统V具有cuserid()函数,该函数使用实际用户ID而不是有效用户ID。 cuserid()函数包含在1988版本的POSIX中,但已从1990版本中删除。它存在于SUSv2中,但已在POSIX.1-2001中删除。


TL; DR

cuserid()函数不可移植,并且不能移植到Mac OSX。

10-05 22:08