出力タイプ
その他
プロジェクトについての設定は、スクリプト実行時の引数、および設定ファイルにて指定するものとする。
くらいか?
この程度であれば、XML の キー指定でタグ置換を行えばよさそう。ただし、Debug, Release の両方への設定が簡単に指定できることが望ましい。
という感じ。ただし、Makefile.am 内で指定されている .h は必要だが、ソース情報は必要ない場合がある。従って、Makefile.am から何の情報を取り出すかは明確に区別する。 そんな感じ。
% ruby vcprogen.rb --name followLine --type exe --sources followLine.cpp % ruby vcprogen.rb --name vxv --type lib --codes `find . -name "Makefilea.am"` % ruby vcprogen.rb vxv_proj.txt --headers `find . -name "Makefile.am"` \ --sources `find . -name "Makefile.am" ! -path "*/c/*"`
% ruby vcprogen.rb --name vxv2 --type lib --mask "cpp,h" \ --headers "`find ${VXV2_PATH} -name "Makefile.am"`" \ --sources "`find ${VXV2_PATH} -name "Makefile.am" \ ! -path "*/monitor/*" ! -path "*/guiCtrl/*" ! -path "*/example/*" \ ! -path "*/tools/*"`" vxv2_cfg.txt
vxv2_cfg.txt の中身
/Configuration/Tool/RuntimeTypeInfo TRUE
/Configuration/Tool/RuntimeLibrary 2
true /Configuration/Tool/PreprocessorDefinitions ;HAVE_CONFIG_H
followLine.exe 用の followLine.vcproj を作る例は以下の通り。
% ruby ${VCPROGEN} --name followLine --type exe --sources "followLine.cpp"
#!/usr/bin/env ruby # # Visual Studio .NET 2003 の vcproj 生成ツール # Satofumi KAMIMURA # $Id$ # 置換処理 def replace(template, key, value, add = false) # 検索パターンの生成 path = key.split('/') - [""] name = path.pop parent = path.pop reg_str = '(<' path.each { |tag| reg_str += tag + '.+?<' } reg_str += parent + '.+?' + name + '=")(.+?)(")' left = template template = '' pattern = Regexp.compile(reg_str, Regexp::MULTILINE) while left =~ pattern template += $` + $1 + ((add) ? $2 : '') + value + $3 left = $' end return template + left end # ファイルの行毎に置換処理 def replaceFromFile(template, config_file) open(config_file) { |io| while line = io.gets tags = line.chomp.split(/\s/, 2) if tags.size() >= 2 if tags[0].downcase == "true" add_tags = tags[1].split(/\s/, 2) template = replace(template, add_tags[0], add_tags[1], true) else template = replace(template, tags[0], tags[1]) end end end return template } rescue STDERR.puts "replaceFromFile: Warning: #$!" end # Makefile の指定タグに指定されているファイルを展開 # include パスを追加 def addIncludes(includes, file) includes.push(File.dirname(file)) end # 1行分の行の取り出し def parseLine(line, io, dir_path) while line[-1,1] == '\\' line = line.chop + io.gets end files = line.split files.map! { |file| dir_path + '/' + file } return files.join(' ') end # Makefile.am を展開する def extendMakefile(file, keyword = 'SOURCES') pattern = Regexp.compile('^\w+?_' + keyword + '\s+=') open(file) { |io| while line = io.gets line.strip! if pattern =~ line return parseLine($', io, File.dirname(file)) end end } rescue STDERR.puts "extendMakefile: Warning: #$!" return "" end # コードに含めるファイル一覧を生成 def createFileList(sources, headers, includes, files, mask) files.split(/\s/).each { |file| if File.basename(file) == "Makefile.am" createFileList(sources, headers, includes, extendMakefile(file), mask) next end ext = File.extname(file)[1..-1] if !mask.split(/[,\s]/).index(ext) next end addIncludes(includes, file) if ext == "h" || ext == "hh" headers.push(file) else sources.push(file) end } end # ファイルタグの生成 def createFilesXML(list, offset) tags = '' list.each { |file| tags += offset + '<File RelativePath="' + file.gsub('/', '\\') + "\"></File>\n" } return tags end # ソースファイルを挿入 def insertSources(template, sources) tags = createFilesXML(sources, "\t\t\t") if tags.empty? return end pattern = /(<Filter\s+Name="Source files".+?\}">)(.+?<\/Filter>)/m if template =~ pattern template.sub!(pattern, $1 + "\n" + tags + $2) end end # ヘッダファイルを挿入 def insertHeaders(template, headers) tags = createFilesXML(headers, "\t\t\t") if tags.empty? return end pattern = /<Filter\s+Name="Header files".+?\}">^.+?<\/Filter>/m if template =~ pattern template.sub!(pattern, $1 + "\n" + tags + $2) end end # include/ の生成 def createIncludes(template, includes, files) targets = [] files.split(/\s/).each { |file| if File.basename(file) == "Makefile.am" targets += extendMakefile(file, "HEADERS").split(' ') else includes << file end } offset = "\t\t\t\t" cmd = 'del /q include; ' + "\n" + offset + 'mkdir include; ' + "\n" targets.each { |file| cmd += offset + 'copy ' + file.gsub('/', '\\') + ' include\; ' + "\n" } return replace(template, '/Configuration/Tool/CommandLine', cmd.chomp) end # 追加のインクルードパスを挿入 def insertIncludes(template, includes) replace = '.\; .\include; ' + includes.uniq.join('; ').gsub('/', '\\') + ';' path = "/Configuration/Tool/AdditionalIncludeDirectories" return replace(template, path, replace) end # lib 生成用テンプレート lib_template = <<-EOB <?xml version="1.0" encoding="shift_jis"?> <VisualStudioProject ProjectType="Visual C++" Version="7.10" Name="lib_template" ProjectGUID="{E35DE899-8736-4A8E-A604-821469165AF1}" RootNamespace="lib_template" Keyword="ManagedCProj"> <Platforms> <Platform Name="Win32"/> </Platforms> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="4" CharacterSet="2" ManagedExtensions="FALSE"> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=";" PreprocessorDefinitions="WIN32;_DEBUG;_LIB" MinimalRebuild="TRUE" BasicRuntimeChecks="0" RuntimeLibrary="1" RuntimeTypeInfo="FALSE" WarningLevel="3" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLibrarianTool"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool" CommandLine=";"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" ManagedExtensions="FALSE"> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=";" PreprocessorDefinitions="WIN32;NDEBUG;_LIB" MinimalRebuild="TRUE" RuntimeLibrary="0" RuntimeTypeInfo="FALSE" WarningLevel="3" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\\$(ProjectName).exe" LinkIncremental="1" GenerateDebugInformation="TRUE"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool" CommandLine=";"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> </Filter> <Filter Name="Header files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> </Filter> <Filter Name="Resource files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> EOB # exe 生成用テンプレート exe_template = <<-EOB <?xml version="1.0" encoding="shift_jis"?> <VisualStudioProject ProjectType="Visual C++" Version="7.10" Name="exe_template" ProjectGUID="{BA46C739-97CD-4F68-9F3D-ECF9759134CE}" RootNamespace="exe_template" Keyword="ManagedCProj"> <Platforms> <Platform Name="Win32"/> </Platforms> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" ManagedExtensions="FALSE"> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=";" PreprocessorDefinitions="WIN32;_DEBUG" MinimalRebuild="TRUE" BasicRuntimeChecks="0" RuntimeLibrary="1" RuntimeTypeInfo="FALSE" WarningLevel="3" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\\$(ProjectName).exe" LinkIncremental="2" SuppressStartupBanner="TRUE" GenerateDebugInformation="TRUE" AssemblyDebug="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool" CommandLine=";"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="$(SolutionDir)$(ConfigurationName)" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" ManagedExtensions="FALSE"> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories=";" PreprocessorDefinitions="WIN32;NDEBUG" MinimalRebuild="TRUE" RuntimeLibrary="0" RuntimeTypeInfo="FALSE" WarningLevel="3" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" OutputFile="$(OutDir)\\$(ProjectName).exe" LinkIncremental="1" GenerateDebugInformation="TRUE"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool" CommandLine=";"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> </Configurations> <References> </References> <Files> <Filter Name="Source files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> </Filter> <Filter Name="Header files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> </Filter> <Filter Name="Resource files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> </Filter> </Files> <Globals> </Globals> </VisualStudioProject> EOB # 使い方を表示して終了 def printUsage() print \ "usage:\n" \ "\t% ruby " + __FILE__ + " [options] <config.txt>\n" \ "\n" \ "options: \n" \ "--name <project name> specify project name\n" \ "--type <exe, lib> specify project output type\n" \ "--mask \"cpp,c,h\" specify handled file type\n" \ "--sources \"<Makefile.am list>\" to create sources list\n" \ "--headers \"<Makefile.am list>\" to create include folder\n" \ "--codes \"<Makefile.am list>\" means sourcesb and headers option\n" \ "\n" exit end # メイン処理 if ARGV.empty? printUsage() end # オプションの判定 pre_arg = nil proj_name = nil proj_type = nil proj_mask = "c,cpp,h" proj_sources = nil proj_headers = nil files = [] ARGV.reverse.each { |arg| case arg when /--name/ proj_name = pre_arg.split('.')[0] files.shift when /--type/ if pre_arg == "exe" || pre_arg == "lib" proj_type = pre_arg end files.shift when /--mask/ proj_mask = pre_arg files.shift when /--sources/ proj_sources = pre_arg files.shift when /--headers/ proj_headers = pre_arg files.shift when /--codes/ proj_sources = pre_arg proj_headers = pre_arg files.shift else files.unshift(arg) end pre_arg = arg } config_file = files.shift if proj_name == nil print "name is not specified!\n" printUsage() end if proj_type == nil print "type is not specified!\n" printUsage() end template = (proj_type == "exe") ? exe_template : lib_template # プロジェクト名の置換 template = replace(template, "/VisualStudioProject/Name", proj_name) template = replace(template, "/VisualStudioProject/RootNamespace", proj_name) # コンフィグファイル指定の要素を置換 if config_file template = replaceFromFile(template, config_file) end sources = [] headers = [] includes = [] # source files, include path の調整 if proj_sources createFileList(sources, headers, includes, proj_sources, proj_mask) end # include folder の生成 if proj_headers template = createIncludes(template, includes, proj_headers) end # sources, headers, includes の反映 insertSources(template, sources) insertHeaders(template, headers) template = insertIncludes(template, includes) # プロジェクトファイルの生成 open(proj_name + '.vcproj', 'w') { |io| io.print template }
以上