- PR -

sedコマンドを使って選択的に置換する方法について

投稿者投稿内容
juice
会議室デビュー日: 2005/02/14
投稿数: 9
投稿日時: 2005-02-14 21:23
こんにちは。juiceと申します。
これまでWindowsの環境で開発を行っていたのですがLinuxの環境で開発を行う必要が生じたためLinux上で使用するmakefileを書いています。

makefileの中でsedコマンドを使用し、選択的に置換を行いたいのですが、何かよい方法をご存知の方がいらっしゃいましたらご教授ください。

現在以下のようなことをmakefileで行いたく、よい案を模索中です。

  1. ディレクトリ「change」直下のソースAAA.cをCCC_AAA.c、ヘッダBBB.hをCCC_BBB.hの名前でmake用のディレクトリ以下にコピーする。
  2. コピーしたCCC_AAA.c内でincludeしているのはBBB.hなのでCCC_BBB.hをincludeするように置換する。
  3. ただし、CCC_AAA.c内ではディレクトリ「change」以外からincludeしているヘッダファイルもあるので、これらについては"CCC_"の付かないファイル名で参照しなければならない。サブディレクトリ内のファイルも同じ。
  4. コンパイルはmake用のディレクトリ以下にコピーしたソース群で行う。
  5. ソースの修正はAAA.cに対して行い、makeのたびにCCC_AAA.c/.hが作られ、これをもとにコンパイルが行われる。

上記条件のうち3を除いた条件(すべてCCC_???.hを見に行く)をクリアしたmakefileは出来たのですが、3を実現できる方法がわかりません。

ちなみに、現在は以下のように置換しています。

コード:
RULE = sed -e "s/^\\#include <\\(.*\\)>/\\#include <CCC_\\1>/"\\
	-e 's/^\\#include "\\(.*\\)"/\\#include "CCC_\\1"/' $< 

CCC_sorce1.c : sorce1.c
	$(RULE)
CCC_sorce2.c : sorce2.c
	$(RULE)
	 :
	 :
ここ以下、ひたすら名前を変更するファイル名を指定。



理想としては、
コード:
  CHANGEHEADDER = A.h B.h C.h D.h E.h F.h


のようにCCC_つきのファイル名で参照してほしいヘッダのみ指定し、CHANGEHEADDERにあてはまるファイル名があった場合のみソース内で置換を行う、というようにしたいと考えていますが、このような方法はないのでしょうか?

最悪の場合は

  1. CCC_の付かないファイル名で参照してほしい場合のみ、ソース上で"include"直後のスペースを増やすなどして置換を回避する。(今は一時的にこれを採用していますが、ソースに無駄な改変が入るためできれば採用したくない)
  2. 「-e 's/^\\#include "change.h"/\\#include "CCC_change.h"/' $< 」など、"CCC_"付きで見てほしいヘッダを指定したsedコマンドにする。(-e…の行が20行以上になりスマートでないためあまり採用したくない)

のどちらかの方法で決着をつけようかと思っています。

質問文が長くなってしまい申し訳ありません。
なにか心当たりのある方がいらっしゃればヒントをいただきたく存じます。
よろしくお願いします。
Uta
常連さん
会議室デビュー日: 2004/05/17
投稿数: 37
投稿日時: 2005-02-15 09:59
引用:

ディレクトリ「change」直下のソースAAA.cをCCC_AAA.c、ヘッダBBB.hをCCC_BBB.hの名前でmake用のディレクトリ以下にコピーする。


このような経験がありませんので伺いたいのですが、ソースファイルやヘッダファイルを
コピーする際にリネームするのってよく行われるものなのでしょうか?
make用のディレクトリを作成しているのならば、リネームせずに単純にコピーしてしまえば
そもそもソース内のinclude宣言部を書換する必要もなくなるのではないかなと考えてしまいました。


さて、本題の部分に関してですが
普通のシェルスクリプトならば、awkかperlに投げるもしくはcsh等の
シェルスクリプトにして配列でも使えばできそうだなと思うのですが、
makefileということで、/bin/shでもできるように考えてみました。

コード:
#!/bin/sh

set 'file1.txt' 'file2.txt' 'file3.txt' 'file4.txt'

while [ $# -gt 0 ]
do
  echo $1   #(←半角$では反映されなかったので全角記号にしてあります)
  shift
done


位置パラメータを使って、リネームしたいヘッダファイルを回しています。
あとは、do - done 内部をカスタマイズして頂ければできるかな、と。
juice
会議室デビュー日: 2005/02/14
投稿数: 9
投稿日時: 2005-02-15 11:23
Utaさん、ご回答ありがとうございます。
引用:

Utaさんの書き込み (2005-02-15 09:59) より:
このような経験がありませんので伺いたいのですが、ソースファイルやヘッダファイルを
コピーする際にリネームするのってよく行われるものなのでしょうか?
make用のディレクトリを作成しているのならば、リネームせずに単純にコピーしてしまえばそもそもソース内のinclude宣言部を書換する必要もなくなるのではないかなと考えてしまいました。


よくあるかどうかはわからないのですが、今回の場合はファイル名に一意のコードを含める必要があるため、このようなことをしています。makeの度にmakefileでやらなくとも一度ざっと変換してしまえば楽なのですが、元ソースが別途更新される可能性があるため、更新された場合に自分のモジュールに反映しやすいようにmakefileを利用しようと考えました。…うまく説明できないのですがお分かりいただけたでしょうか?

肝心のシェルスクリプトなのですが、自分でいろいろ調べながら書いていただいたコードの意味を理解しているところです。
ある程度理解が進んだところで、こちらにご報告させていただこうと思っています。ありがとうございました。
juice
会議室デビュー日: 2005/02/14
投稿数: 9
投稿日時: 2005-02-15 17:01
お世話になっております。
Utaさんに教えていただいた方法を元に、スクリプトを書いておりますがスクリプトの書き方が正しくないのか、syntax errorが出てしまいます。何かお分かりの方がいらっしゃれば、ご教授願います。

現在のコードは以下のようになっています。
コード:
☆元のコード☆

1 RULE = sed -e "s/^\#include <\(.*\)>/\#include <CCC_\1>/"\
2  -e 's/^\#include "\(.*\)"/\#include "CCC_\1"/' $<
3 
4 CCC_sorce1.c : sorce1.c
5  $(RULE)
6 CCC_sorce2.c : sorce2.c
7  $(RULE)

以下のように変更
   ↓

☆現在のコード@☆
1 CCC_sorce1.c : sorce1.c
2  set $(CHANGE_HEADER:%='%') #CHANGE_HEADER = A.h B.h C.h…のように
                   #変換してほしいヘッダ名を連記。
3  while [ $# -gt 0 ]
4  do
5  sed -e "s/^\#include <>/\#include <CCC_>/"\
6  -e 's/^\#include ""/\#include "CCC_"/' $<
7  shift
8  done


このようにmakefileを書き換え、makeを行うと以下のようなエラーメッセージが出力されます。(本題にかかわると思われる部分のみ抜き出しました。他に出力されているエラーメッセージはありません。)
コード:
set 'A.h' 'B.h' 'C.h' 'D.h'… #CHANGE_HEADERに指定したファイル名を列挙。

while [ -gt 0 ]
/bin/sh: -c: line 2: syntax error: unexpected end of file


素人考えですが、「$#」,「$1」が効いていないように見えます。
また、以下のように書き換えて実行すると以下のようなエラーが出力されます。
コード:
☆現在のコードA☆

1 CCC_sorce1.c : sorce1.c
2  set $(CHANGE_HEADER:%='%') #CHANGE_HEADER = A.h B.h C.h…のように
                #変換してほしいヘッダ名を連記。
3  sed -e "s/^\#include <>/\#include <CCC_>/"\
4  -e 's/^\#include ""/\#include "CCC_"/' $<

☆実行結果☆
set 'A.h' 'B.h' 'C.h' 'D.h'… #CHANGE_HEADERに指定したファイル名を列挙。
sed -e "s/^\#include <>/\#include <CCC_>/"\
-e 's/^\#include ""/\#include "CCC_"/' sorce1.c
※ここ以下sorce1.cの中身がすべて出力されます。置換はなされていません。


根本的に書き方が間違っているのか、あるいは別の原因(自分の開発環境特有の設定など)で「$#」,「$1」が効いていないのかわからないため、続けて質問させていただきました。

お忙しいとは存じますがよろしくお願いいたします。

[ メッセージ編集済み 編集者: juice 編集日時 2005-02-15 17:06 ]
MMX
ぬし
会議室デビュー日: 2001/10/26
投稿数: 861
投稿日時: 2005-02-15 18:36
ヘッダファイルの読み込みについては,コンパイル時に I オプションを付してヘッダのあるディレクトリを追加することができます。

cc -I /path/to/directory1/ -I /path/to/directory2/ ...

CCC_AAA.cの作成は行って、 インクルードには 「change」を追加
ですみませんか?
A.h B.h C.h D.h E.h F.h には CCCを付けない。

ソースの変更なら #ifdef などがノーマルと思いますが
=================================================
あるいは、インクルード順位の最高位のディレクトリに 、BBB → #INCLUDE CCC_BBB をする間接インクルードの中継地でも置くとか。ですね


[ メッセージ編集済み 編集者: MMX 編集日時 2005-02-16 09:49 ]
juice
会議室デビュー日: 2005/02/14
投稿数: 9
投稿日時: 2005-02-15 20:01
MMXさん、ご回答ありがとうございます。
引用:
ヘッダファイルの読み込みについては,コンパイル時に I オプションを付してヘッダのあるディレクトリを追加することができます。
cc -I /path/to/directory1/ -I /path/to/directory2/ ...


"CCC_"を付加しないソース群でmakeした場合では正常にオブジェクトが生成されるため、ヘッダのパスが通っていない、ということはないと思います。"-I"オプションも正しく使われています。
引用:
CCC_AAA.cの作成は行って、 インクルードには 「change」を追加
ですみませんか?
A.h B.h C.h D.h E.h F.h には CCCを付けない。
ソースの変更なら #ifdef などがノーマルと思いますが


"CCC_"をつけない、という選択肢はないようなのです…(技術的でなく他の事情により)
ソース自身に修正を加えると、元ソースが改変された場合に再度同じ修正を自分のソースに加えなければならないと考えたため、"#ifdef"は使わずにmakefileのみで実現しようとしています。
以下引用を参照のこと。
引用:
よくあるかどうかはわからないのですが、今回の場合はファイル名に一意のコードを含める必要があるため、このようなことをしています。makeの度にmakefileでやらなくとも一度ざっと変換してしまえば楽なのですが、元ソースが別途更新される可能性があるため、更新された場合に自分のモジュールに反映しやすいようにmakefileを利用しようと考えました。…うまく説明できないのですがお分かりいただけたでしょうか?


また、MMXさんのおっしゃる"インクルードには 「change」を追加"の意味がわかりかねるのですが、具体的にはどのような方法を指すのでしょうか?
お手数おかけしますがお答えいただけると幸いです。

やはりこのような方法はないのでしょうか…
私の作成したシェルスクリプトが基本的に間違っているかもしれないので、「そもそも書き方が違う」といったヒントでもいただければありがたく存じます。
よろしくお願いいたします。
Uta
常連さん
会議室デビュー日: 2004/05/17
投稿数: 37
投稿日時: 2005-02-16 08:34
すみません、勘違いをしていました。
makefileを作るためのスクリプトを作成するのだと思っていました。
makefile内に記述しておくことでsedを呼び出せるのですねぇ。。
知りませんでした。


オープンソースによく見られるように、
configure(シェルスクリプト) → makefile作成 → make
というように手順を分けることは難しいのでしょうか?
juice
会議室デビュー日: 2005/02/14
投稿数: 9
投稿日時: 2005-02-16 14:24
引用:
Utaさんの書き込み (2005-02-16 08:34) より:
オープンソースによく見られるように、
configure(シェルスクリプト) → makefile作成 → make
というように手順を分けることは難しいのでしょうか?


configureというのがよくわからなかったので調べてみたのですが、configureの書き方がわからないので時間がかかりそうです。。。
makefileは自分でがりがり書くものだと思っていました。

ひとつお聞きしたいのですが、「configure(シェルスクリプト) → makefile作成 → make というように手順を分ける」と何かいいことがあるのでしょうか?今現在問題となっているポイント(CCC_をつけたファイル名に対応する)を除けば正しくコンパイル〜リンクが行えているのであまりここから大幅に変更はしたくないと考えているのですが。

スキルアップ/キャリアアップ(JOB@IT)