【解決!】ignoring invalid character `#' in expression

Cortex-A5 CMSISのリンカスクリプトをベースにコンパイル環境を構築していると こんなエラーが発生しました。

ld.exe:ARMCA5.ld:1: ignoring invalid character `#' in expression
ld.exe:ARMCA5.ld:1: syntax error
collect2.exe: error: ld returned 1 exit status

原因はARMCA5.ldのこの記述です。

#include "mem_ARMCA5.h"  ← これ!

MEMORY
{
  ROM (rx)   : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
  L_TTB (rw) : ORIGIN = __TTB_BASE, LENGTH = __TTB_SIZE 
  RAM (rwx)  : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
}
...snip...

Cプリプロセッサの書式で書いてありますが、リンカはCプリプロセッサ機能を持っていないためエラーになります。

解決方法

どうやら、このリンカスクリプトは一旦Cプリプロセッサに通すことを前提に書かれているようです。

というとで、gccを使ってプリプロセスを実行してやります。

arm-none-eabi-gcc -I <mem_ARMCA5.hのあるディレクトリ> -nostdinc -P -E -x c ARMCA5.ld -o ARMCA5.generated.ld

このコマンドで生成したARMCA5.generated.ldを使ってリンカを起動すれば正常にリンクできます。

応用編

ARMCA5.ldやmem_ARMCA5.hを変更した際に自動的にARMCA5.generated.ldが生成できると便利ですね。そこで、こんなMakefileを作ってみました。これ単体で使ってもあまり意味はないと思いますので、ビルド用のMakefileに組み込んで使ってください。

CC = arm-none-eabi-gcc
LDSCRIPT_CFLAGS = -I ./Device/include -nostdinc -MMD -MP -P -E -x c
LDSCRIPT_SRC = ./Device/Source/ARMCA5.ld
LDSCRIPT = ./Device/Source/ARMCA5.generated.ld
LDSCRIPT_DEPEND = $(LDSCRIPT:.ld=.d)
DEPENDS = $(LDSCRIPT_DEPEND)

all: $(LDSCRIPT)

$(LDSCRIPT): $(LDSCRIPT_SRC)
  $(CC) $(LDSCRIPT_CFLAGS) $< -o $@
  sed -i "s|$(notdir $(basename $<)).o|$@|" $(LDSCRIPT_DEPEND)

ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif

なお、LDSCRIPT_CFLAGSの“./Device/include”はmem_ARMCA5.hがあるディレクトリです。環境によって書き換えてください。

Makefileサンプルの解説

-MMD -MPでARMCA5.generated.ldの依存関係ファイルを生成し、それをincludeすることで、ARMCA5.generated.ldの自動生成を実現しています。

ただし、これだけでは依存関係ファイルは以下のように生成されてしまい、正常にmakeされません。

ARMCA5.o: Device/Source/ARMCA5.ld Device/include/mem_ARMCA5.h

Device/include/mem_ARMCA5.h:

そこで、sedを用いて以下の様に書き換えています。

Device/Source/ARMCA5.generated.ld: Device/Source/ARMCA5.ld Device/include/mem_ARMCA5.h

Device/include/mem_ARMCA5.h:

これで正しく依存関係ファイルが生成できました。

もっと簡単な方法

いっそのこと、#includeを削除してリンカスクリプトの構文に書き換えてしまうのもありですね。