configureでヘッダやライブラリのパスを指定する方法

January 20,2017 12:03 AM
Category:[C/C++]
Tag:[C/C++]
Permalink

configureでヘッダやライブラリのパスを指定する方法を紹介します。

1.問題点

とあるCライブラリをインストールしようと思い、configureを実行したところ、下記のようなエラーが発生しました。

% ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
 :
checking whether byte ordering is bigendian... no
checking size of void *... 8
checking for elf_begin in -lelf... yes
checking for dwarf_def_macro in -ldwarf... no
configure: error: libdwarf is not found

libdwarfというライブラリがみつからないようです。

ということで、configureを実行するときにライブラリやヘッダのパスを指定する方法を紹介します。

2.configureを実行するときにライブラリやヘッダのパスを指定する

configureを実行するときにライブラリやヘッダのパスを指定するには次のようにします。

./configure LDFLAGS="-L/usr/local/lib" CFLAGS="-I/usr/local/include"

LDFLAGSの右辺にライブラリのパス、CFLAGSの右辺にヘッダのパスを記述します。

指定可能なオプションは"./configure --help"で表示されます。

参考にhelpの内容を掲載しておきます。

% ./configure --help
`configure' configures tracef 0.16 to adapt to many kinds of systems.
 
Usage: ./configure [OPTION]... [VAR=VALUE]...
 
To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.
 
Defaults for the options are specified in brackets.
 
Configuration:
  -h, --help              display this help and exit
      --help=short        display options specific to this package
      --help=recursive    display the short help of all the included packages
  -V, --version           display version information and exit
  -q, --quiet, --silent   do not print `checking ...' messages
      --cache-file=FILE   cache test results in FILE [disabled]
  -C, --config-cache      alias for `--cache-file=config.cache'
  -n, --no-create         do not create output files
      --srcdir=DIR        find the sources in DIR [configure dir or `..']
 
Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [/usr/local]
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                          [PREFIX]
 
By default, `make install' will install all the files in
`/usr/local/bin', `/usr/local/lib' etc.  You can specify
an installation prefix other than `/usr/local' using `--prefix',
for instance `--prefix=$HOME'.
 
For better control, use the options below.
 
Fine tuning of the installation directories:
  --bindir=DIR            user executables [EPREFIX/bin]
  --sbindir=DIR           system admin executables [EPREFIX/sbin]
  --libexecdir=DIR        program executables [EPREFIX/libexec]
  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
  --libdir=DIR            object code libraries [EPREFIX/lib]
  --includedir=DIR        C header files [PREFIX/include]
  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
  --infodir=DIR           info documentation [DATAROOTDIR/info]
  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
  --mandir=DIR            man documentation [DATAROOTDIR/man]
  --docdir=DIR            documentation root [DATAROOTDIR/doc/tracef]
  --htmldir=DIR           html documentation [DOCDIR]
  --dvidir=DIR            dvi documentation [DOCDIR]
  --pdfdir=DIR            pdf documentation [DOCDIR]
  --psdir=DIR             ps documentation [DOCDIR]
 
Program names:
  --program-prefix=PREFIX            prepend PREFIX to installed program names
  --program-suffix=SUFFIX            append SUFFIX to installed program names
  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
 
Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --disable-dependency-tracking  speeds up one-time build
  --enable-dependency-tracking   do not reject slow dependency extractors
 
Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CXX         C++ compiler command
  CXXFLAGS    C++ compiler flags
  CXXCPP      C++ preprocessor
 
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
 
Report bugs to the package provider.

3.参考サイト

参考サイトは下記です。ありがとうございました。

What is the correct syntax to add CFLAGS and LDFLAGS to "configure"?

Comments [0] | Trackbacks [0]

C/C++プログラム実行時の関数をトレースする方法

January 18,2017 12:03 AM
Category:[C/C++]
Tag:[C/C++]
Permalink

C/C++プログラム実行時の関数をトレースする方法を紹介します。

1.はじめに

C/C++プログラムで実行時の関数をトレースする場合、printf()などを埋め込んでログに出力することが少なくないと思います。

が、その方法ではログ出力するためにプログラムに手を入れなくてはならなず、非効率です。

また規模の大きなプログラムでは現実的な解決方法ではありません。

printf()を埋め込まずにトレースできないか、方法を探していたところ、標準でそのような機能があることをみつけました。

仕組みは、gccでトレースしたいプログラムファイルのコンパイル時に、コンパイルオプション"-finstrument-functions"を付与することで、関数の実行開始時および復帰時に下記のフック関数を呼び出せるようになります。

void __cyg_profile_func_enter(void* func, void* caller);
void __cyg_profile_func_exit(void* func, void* caller);

あとはこの2つの関数にログ出力を実装し、ライブラリとして引き込めばOKです。

ということで、C/C++プログラムを動かして関数をトレースする方法を紹介します。

2.ソースコード

まず、トレース用の関数(trace.cpp)です。

前述の__cyg_profile_func_enter()、__cyg_profile_func_exit()を実装し、トレース情報を出力します。

trace.cpp

#include <dlfcn.h>
#include <iostream>
 
extern "C" {
    void __cyg_profile_func_enter(void* func, void* caller);
    void __cyg_profile_func_exit(void* func, void* caller);
}
 
const char* to_name(void* address) {
    Dl_info dli;
    if (0 != dladdr(address, &dli)) {
        return dli.dli_sname;
    }
    return 0;
}
 
void __cyg_profile_func_enter(void* func, void* caller) {
    const char* name = to_name(func);
    if (name) {
        std::cout << "start:" << name << std::endl;
    } else {
        std::cout << "start:" << func << std::endl;
    }
}
 
void __cyg_profile_func_exit(void* func, void* caller) {
    const char* name = to_name(func);
    if (name) {
        std::cout << "end  :" << name << std::endl;
    } else {
        std::cout << "end  :" << func << std::endl;
    }
}

そしてトレース対象となるC++サンプル関数(sample.cpp/sample.c)です。

サンプルでは、main()→hello_world1()→hello_world2()の順に起動するようにします。

ファイルの内容は同じですが、C用とC++用に異なるファイル名で2つ作成します。

sample.cpp/sample.c

#include <stdio.h>
 
void hello_world2(void) {
    printf( "Hello World2!\n" );                                                                                                                              }
 
void hello_world1(void) {
    printf( "Hello World1!\n" );
    hello_world2();
}
 
int main(void) {
    hello_world1();
    return 0;
}

3.コンパイル

トレース用関数(trace.cpp)

% g++ -fPIC -shared trace.cpp -o libctrace.so -ldl

トレース対象のC++サンプル関数(sample.cpp)

% g++ -fPIC -finstrument-functions sample.cpp -o helloworld_cpp

トレース対象のC++サンプル関数(sample.c)

% gcc -fPIC -finstrument-functions sample.c -o helloworld_c

これで下記のとおり、サンプルのhelloworld_c、helloworld_cppと、トレース用ライブラリlibctrace.soが作られます。

% ls -l
-rwxr-xr-x. 1 hoge hoge 7327  1月 17 23:21 2017 helloworld_c
-rwxr-xr-x. 1 hoge hoge 8256  1月 17 23:30 2017 helloworld_cpp
-rwxr-xr-x. 1 hoge hoge 8498  1月 17 23:23 2017 libctrace.so
-rw-r--r--. 1 hoge hoge  342  1月 17 23:20 2017 sample.c
-rw-r--r--. 1 hoge hoge  342  1月 17 23:12 2017 sample.cpp
-rw-r--r--. 1 hoge hoge  784  1月 17 23:23 2017 trace.cpp

4.実行

実行時は環境変数"LD_PRELOAD"を設定します。

LD_PRELOADにlibctrace.soを指定することでこのライブラリが最優先で読み込まれ、__cyg_profile_func_enter()および__cyg_profile_func_exit()が実行されます。

helloworld_cpp(C++)の実行

%  LD_PRELOAD=./libctrace.so ./helloworld_cpp | c++filt                                                                            
start:main
start:hello_world1()
Hello World1!
start:hello_world2()
Hello World2!
end  :hello_world2()
end  :hello_world1()
end  :main

c++filtはC++やJavaのシンボルをデマングルするコマンドです。

helloworld_cpp(C++)でc++filtを使わずに実行

% LD_PRELOAD=./libctrace.so ./helloworld_cpp                                                                                        
start:main
start:_Z12hello_world1v
Hello World1!
start:_Z12hello_world2v
Hello World2!
end  :_Z12hello_world2v
end  :_Z12hello_world1v
end  :main

helloworld_c(C)の実行

% LD_PRELOAD=./libctrace.so ./helloworld_c                                                                                          
start:main
start:hello_world1
Hello World1!
start:hello_world2
Hello World2!
end  :hello_world2
end  :hello_world1
end  :main

なお、実行環境によってトレース関数内で使っているdladdr()が正常に動作しない(=アドレスから関数名が取得できない)ケースがありました。

また、トレース用ライブラリのコンパイルで"-ldl"を指定しないと、実行時に下記のエラーが発生することを確認しています。

./helloworld_cpp: symbol lookup error: ./libctrace.so: undefined symbol: dladdr

5.参考サイト

参考サイトは下記です。ありがとうございました。

Comments [0] | Trackbacks [0]

Movable Typeで承認ワークフロー

January 11,2017 12:03 AM
Category:[MTDDC]
Tag:[MTDDC]
Permalink

遅くなりましたが「MTDDC Meetup Tokyo 2016」で発表した「Movable Typeで承認ワークフロー」のスライドを公開します。

スライドはワークフローおよびWorkflowプラグインについての解説で、次のような構成になっています。

  • ワークフローの概要
  • ワークフロープラグイン開発のきっかけ
  • 苦労した点
  • Workflowプラグインの概要
  • 必要な設定
  • その他の機能
  • 実演(スライドなしです、すいません)

また下記のリンクから当日の音声も聴くことができます。

Movable Typeで承認ワークフロー

Comments [0] | Trackbacks [0]
 1  |  2  |  3  |  4  |  5  | All pages