我正在尝试使用Make在OS X上编译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
答案 0 :(得分:0)
您应该设置#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手册页注释:
System V具有
cuserid()
功能,该功能使用真实用户ID而不是有效用户ID。cuserid()
函数包含在1988版本的POSIX中,但已从1990版本中删除。它存在于SUSv2中,但在POSIX.1-2001中删除。
cuserid()
功能无法移植,无法移植到Mac OS X.