質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

3回答

4388閲覧

C言語で共通ヘッダーファイルを含んだソースプログラムのコンパイル方法を教えてください。

kenji267

総合スコア50

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

0クリップ

投稿2018/12/31 04:24

編集2018/12/31 04:51

前提・実現したいこと

「Linuxプログラムインターフェース」を読んでLinuxの学習を進めようとしているのですが、
C言語のコンパイルでつまづいています。

例えば下記ファイルcopy.cをコンパイル時、エラーが発生しています。

発生している問題・エラーメッセージ

tmp/ccldvlfL.o: In function `main': copy.c:(.text+0x58): undefined reference to `usageErr' copy.c:(.text+0xa1): undefined reference to `errExit' copy.c:(.text+0xfb): undefined reference to `errExit' copy.c:(.text+0x128): undefined reference to `fatal' copy.c:(.text+0x163): undefined reference to `errExit' copy.c:(.text+0x181): undefined reference to `errExit' copy.c:(.text+0x19f): undefined reference to `errExit' collect2: ld はステータス 1 で終了しました

該当のソースコード

copy.c

C言語

1#include <sys/stat.h> 2#include <fcntl.h> 3#include "tlpi_hdr.h" 4 5#ifndef BUF_SIZE 6#define BUF_SIZE 1024 7#endif 8 9int 10main(int argc, char *argv[]) 11{ 12 int inputFd, outputFd, openFlags; 13 mode_t filePerms; 14 ssize_t numRead; 15 char buf[BUF_SIZE]; 16 17 if (argc != 3 || strcmp(argv[1], "--help") == 0) 18 usageErr("%s old-file new-file\n", argv[0]); 19 20 /* Open input and output files */ 21 22 inputFd = open(argv[1], O_RDONLY); 23 if (inputFd == -1) 24 errExit("opening file %s", argv[1]); 25 26 openFlags = O_CREAT | O_WRONLY | O_TRUNC; 27 filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 28 S_IROTH | S_IWOTH; /* rw-rw-rw- */ 29 outputFd = open(argv[2], openFlags, filePerms); 30 if (outputFd == -1) 31 errExit("opening file %s", argv[2]); 32 33 /* Transfer data until we encounter end of input or an error */ 34 35 while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0) 36 if (write(outputFd, buf, numRead) != numRead) 37 fatal("couldn't write whole buffer"); 38 if (numRead == -1) 39 errExit("read"); 40 41 if (close(inputFd) == -1) 42 errExit("close input"); 43 if (close(outputFd) == -1) 44 errExit("close output"); 45 46 exit(EXIT_SUCCESS); 47}

上記ファイルで使用しているファイル
tlpi_hdr.h

#ifndef TLPI_HDR_H #define TLPI_HDR_H #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include "get_num.h" /* Declares our functions for handling numeric arguments (getInt(), getLong()) */ #include "error_functions.h" /* Declares our error-handling functions */ typedef enum { FALSE, TRUE } Boolean; #define min(m,n) ((m) < (n) ? (m) : (n)) #define max(m,n) ((m) > (n) ? (m) : (n)) #endif

--
get_num.h

#ifndef GET_NUM_H #define GET_NUM_H #define GN_NONNEG 01 #define GN_GT_0 02 #define GN_ANY_BASE 0100 #define GN_BASE_8 0200 #define GN_BASE_16 0400 long getLong(const char *arg, int flags, const char *name); int getInt(const char *arg, int flags, const char *name); #endif

--
error_functions.h

/* error_functions.h Header file for error_functions.c. */ #ifndef ERROR_FUNCTIONS_H #define ERROR_FUNCTIONS_H /* Error diagnostic routines */ void errMsg(const char *format, ...); #ifdef __GNUC__ /* This macro stops 'gcc -Wall' complaining that "control reaches end of non-void function" if we use the following functions to terminate main() or some other non-void function. */ #define NORETURN __attribute__ ((__noreturn__)) #else #define NORETURN #endif void errExit(const char *format, ...) NORETURN ; void err_exit(const char *format, ...) NORETURN ; void errExitEN(int errnum, const char *format, ...) NORETURN ; void fatal(const char *format, ...) NORETURN ; void usageErr(const char *format, ...) NORETURN ; void cmdLineErr(const char *format, ...) NORETURN ; #endif

試したこと

表示エラーを見ると共通ヘッダーファイル(tlpi_hdr.h、tlpi_hdr.hの共通ヘッダーファイルであるget_num.h、error_functions.h)は読めているようです。
エラーはerror_functions.hで定義している関数が定義されていないということですので、
何らかの方法で関数の定義をする必要があるように思えます。

error_functions.cで定義

#include <stdarg.h> #include "error_functions.h" #include "tlpi_hdr.h" #include "ename.c.inc" /* Defines ename and MAX_ENAME */ #ifdef __GNUC__ __attribute__ ((__noreturn__)) #endif static void terminate(Boolean useExit3) { char *s; /* Dump core if EF_DUMPCORE environment variable is defined and is a nonempty string; otherwise call exit(3) or _exit(2), depending on the value of 'useExit3'. */ s = getenv("EF_DUMPCORE"); if (s != NULL && *s != '\0') abort(); else if (useExit3) exit(EXIT_FAILURE); else _exit(EXIT_FAILURE); } static void outputError(Boolean useErr, int err, Boolean flushStdout, const char *format, va_list ap) { #define BUF_SIZE 500 char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE]; vsnprintf(userMsg, BUF_SIZE, format, ap); if (useErr) snprintf(errText, BUF_SIZE, " [%s %s]", (err > 0 && err <= MAX_ENAME) ? ename[err] : "?UNKNOWN?", strerror(err)); else snprintf(errText, BUF_SIZE, ":"); snprintf(buf, BUF_SIZE, "ERROR%s %s\n", errText, userMsg); if (flushStdout) fflush(stdout); /* Flush any pending stdout */ fputs(buf, stderr); fflush(stderr); /* In case stderr is not line-buffered */ } void errMsg(const char *format, ...) { va_list argList; int savedErrno; savedErrno = errno; /* In case we change it here */ va_start(argList, format); outputError(TRUE, errno, TRUE, format, argList); va_end(argList); errno = savedErrno; } void errExit(const char *format, ...) { va_list argList; va_start(argList, format); outputError(TRUE, errno, TRUE, format, argList); va_end(argList); terminate(TRUE); } void err_exit(const char *format, ...) { va_list argList; va_start(argList, format); outputError(TRUE, errno, FALSE, format, argList); va_end(argList); terminate(FALSE); } void errExitEN(int errnum, const char *format, ...) { va_list argList; va_start(argList, format); outputError(TRUE, errnum, TRUE, format, argList); va_end(argList); terminate(TRUE); } void fatal(const char *format, ...) { va_list argList; va_start(argList, format); outputError(FALSE, 0, TRUE, format, argList); va_end(argList); terminate(TRUE); } void usageErr(const char *format, ...) { va_list argList; fflush(stdout); fprintf(stderr, "Usage: "); va_start(argList, format); vfprintf(stderr, format, argList); va_end(argList); fflush(stderr); exit(EXIT_FAILURE); } void cmdLineErr(const char *format, ...) { va_list argList; fflush(stdout); /* Flush any pending stdout */ fprintf(stderr, "Command-line usage error: "); va_start(argList, format); vfprintf(stderr, format, argList); va_end(argList); fflush(stderr); /* In case stderr is not line-buffered */ exit(EXIT_FAILURE); }

--
ename.c.inc

static char *ename[] = { /* 0 */ "", /* 1 */ "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", "ENXIO", /* 7 */ "E2BIG", "ENOEXEC", "EBADF", "ECHILD", /* 11 */ "EAGAIN/EWOULDBLOCK", "ENOMEM", "EACCES", "EFAULT", /* 15 */ "ENOTBLK", "EBUSY", "EEXIST", "EXDEV", "ENODEV", /* 20 */ "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", /* 25 */ "ENOTTY", "ETXTBSY", "EFBIG", "ENOSPC", "ESPIPE", /* 30 */ "EROFS", "EMLINK", "EPIPE", "EDOM", "ERANGE", /* 35 */ "EDEADLK/EDEADLOCK", "ENAMETOOLONG", "ENOLCK", "ENOSYS", /* 39 */ "ENOTEMPTY", "ELOOP", "", "ENOMSG", "EIDRM", "ECHRNG", /* 45 */ "EL2NSYNC", "EL3HLT", "EL3RST", "ELNRNG", "EUNATCH", /* 50 */ "ENOCSI", "EL2HLT", "EBADE", "EBADR", "EXFULL", "ENOANO", /* 56 */ "EBADRQC", "EBADSLT", "", "EBFONT", "ENOSTR", "ENODATA", /* 62 */ "ETIME", "ENOSR", "ENONET", "ENOPKG", "EREMOTE", /* 67 */ "ENOLINK", "EADV", "ESRMNT", "ECOMM", "EPROTO", /* 72 */ "EMULTIHOP", "EDOTDOT", "EBADMSG", "EOVERFLOW", /* 76 */ "ENOTUNIQ", "EBADFD", "EREMCHG", "ELIBACC", "ELIBBAD", /* 81 */ "ELIBSCN", "ELIBMAX", "ELIBEXEC", "EILSEQ", "ERESTART", /* 86 */ "ESTRPIPE", "EUSERS", "ENOTSOCK", "EDESTADDRREQ", /* 90 */ "EMSGSIZE", "EPROTOTYPE", "ENOPROTOOPT", /* 93 */ "EPROTONOSUPPORT", "ESOCKTNOSUPPORT", /* 95 */ "EOPNOTSUPP/ENOTSUP", "EPFNOSUPPORT", "EAFNOSUPPORT", /* 98 */ "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN", "ENETUNREACH", /* 102 */ "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS", /* 106 */ "EISCONN", "ENOTCONN", "ESHUTDOWN", "ETOOMANYREFS", /* 110 */ "ETIMEDOUT", "ECONNREFUSED", "EHOSTDOWN", "EHOSTUNREACH", /* 114 */ "EALREADY", "EINPROGRESS", "ESTALE", "EUCLEAN", /* 118 */ "ENOTNAM", "ENAVAIL", "EISNAM", "EREMOTEIO", "EDQUOT", /* 123 */ "ENOMEDIUM", "EMEDIUMTYPE", "ECANCELED", "ENOKEY", /* 127 */ "EKEYEXPIRED", "EKEYREVOKED", "EKEYREJECTED", /* 130 */ "EOWNERDEAD", "ENOTRECOVERABLE", "ERFKILL", "EHWPOISON" }; #define MAX_ENAME 133

error_functions.cをコンパイルすると下記エラーが出ます。

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' collect2: ld はステータス 1 で終了しました

確かにmainを使用していないので上記エラーが出ています。
error_functions.hとerror_functions.cの関連がわかればなんとかなると思っているのですが、恥ずかしながら手詰まりになっています。
この辺りができればなんとか学習を進めていけるのではないかと考えています。
ご教授いただければ助かります。宜しくお願いします。

補足情報(FW/ツールのバージョンなど)

vagrant環境で上記を試しています。
OS,gccのバージョンは下記になります。

CentOS release 6.9 (Final)
gcc version 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

copy.c:(.text+0x58): undefined reference to `usageErr'

usageErr という関数の定義がありません。
標準関数でもないし、ソースファイルが不足してるかライブラリの指定が不足しているか、あるいは単なる書き忘れか、ですね。
このエラーの該当の名前の関数をどうにかしましょう


って、ソースファイルが不足しているテですか。
複数のソースファイルをコンパイル後、リンクする必要があります
とりあえず、
gcc copy.c error_functions.c
でコンパイルしてみましょう

投稿2018/12/31 04:42

編集2018/12/31 04:51
y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kenji267

2018/12/31 04:49

回答ありがとうございます。 usageErr という関数の定義関連は「試したこと」を見れば私なりに対応し、その旨記載しています。 そこでわからないので記載しました。
y_waiwai

2018/12/31 04:51

追記しました
kenji267

2018/12/31 05:44

a.outでコンパイルファイルができ、ファイルのコピーができました。 ご指摘通り複数のソースファイルを実行させる方法が全くわからないことによる質問です。
y_waiwai

2018/12/31 06:00 編集

gcc copy.c error_functions.c でコンパイルすると、以下の動作を行います ・copy.c をコンパイルして copy.oを生成する ・error_functions.c をコンパイルしてerror_functions.oを生成 ・copy.o と error_functions.o をリンクして、a.out(Windowsなら a.exe)を生成する 別回答にもありますが、コンパイルだけ、リンクだけ、ということも可能ですんで、gccのオプションなどを調べてみるといろいろわかるかと思います
y_waiwai

2018/12/31 05:58

ちなみに、最初に提示されたエラーは、この3つ目のリンクの動作のときに、あるはずの関数がどこにもない!というgcc(リンカ)の叫びだった、ということがわかろうかとおもいます
guest

0

複数のソースファイルを実行させる方法が全くわからない事による質問

gccのコマンドを
gcc -o test test.c
上記のようにコンパイルの呪文みたいに使用していた。

Linuxの学習をしたいが、Cのコンパイルで理解不足が大きいため、急ぎ質問した。

下記辺り参照
複数ファイルのコンパイル
初心者を意識したgccコマンド使用方法を記載
gccの使用方法

投稿2018/12/31 06:08

kenji267

総合スコア50

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

分割コンパイルならこうですね。

sh

1gcc コンパイルオプション copy.c -c 2gcc コンパイルオプション error_functions.c -c 3gcc copy.o error_functions.o -o program

投稿2018/12/31 05:11

編集2018/12/31 05:13
fu7mu4

総合スコア1088

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kenji267

2018/12/31 05:48

gccの使用方法の具体的な記載ありがとうございます。 分割コンパイルの知識が全くなかったので、面倒でもこういうステップを入れて頂けると理解しやすく助かります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問