<   2013年 11月 ( 12 )   > この月の画像一覧

commands

前へ 目次 次へ

参照: cabal-install 関連のリンク

今週仕事が忙しくて cabal-install の解読ができなかったらなにをやっていたのかすっかり忘れてしまっていた。過去記事を読み返してみて、今回の記事の目的は Main.hs の main 関数の定義に出てくる

commandsRun globalCommand commands args

の第2引数の commands の解読だということがわかった。

commnads の定義は Main.hs の mainWorker 関数の定義の where 句の中にでてくる。

    commands =
      [installCommand         `commandAddAction` installAction
      ,updateCommand          `commandAddAction` updateAction
      ,listCommand            `commandAddAction` listAction
      ,infoCommand            `commandAddAction` infoAction
      ,fetchCommand           `commandAddAction` fetchAction
      ,unpackCommand          `commandAddAction` unpackAction
      ,checkCommand           `commandAddAction` checkAction
      ,sdistCommand           `commandAddAction` sdistAction
      ,uploadCommand          `commandAddAction` uploadAction
      ,reportCommand          `commandAddAction` reportAction
      ,initCommand            `commandAddAction` initAction
      ,configureExCommand     `commandAddAction` configureAction
      ,wrapperAction (buildCommand defaultProgramConfiguration)
                     buildVerbosity    buildDistPref
      ,wrapperAction copyCommand
                     copyVerbosity     copyDistPref
      ,wrapperAction haddockCommand
                     haddockVerbosity  haddockDistPref
      ,wrapperAction cleanCommand
                     cleanVerbosity    cleanDistPref
      ,wrapperAction hscolourCommand
                     hscolourVerbosity hscolourDistPref
      ,wrapperAction registerCommand
                     regVerbosity      regDistPref
      ,wrapperAction testCommand
                     testVerbosity     testDistPref
      ,wrapperAction benchmarkCommand
                     benchmarkVerbosity     benchmarkDistPref
      ,upgradeCommand         `commandAddAction` upgradeAction
      ]

標準モジュールの Distribution.Simple.Command で定義されている commandsRun の型は次のようになるから、

commandsRun :: CommandUI a -> [Command action] -> [String] -> CommandParse (a, CommandParse action)

commands の型は [Command action] という Commnad action 型のリストだ。

Command aciton 型の定義はやはり、Distribution.Simple.Commnad モジュールの中にあり、次のようになっている。

data Command action = Command String String ([String] -> CommandParse action)

3つのコンテナがあり、第1のコンテナが String 型で、第2のコンテナの型が String 型、第3のコンテナが String のリスト [String] を引数とし ComanndParse action を戻り値とする関数になっている。

Command action 型のデータはコンテナの値を直接に入力するのではなく、commandAddAction 関数を使って生成するようになっている。commandAddAction の定義はやはり Distribution.Simple.Command にあり次のような型をしている。

commandAddAction :: CommandUI flags -> (flags -> [String] -> action) -> Command action

第1引数は前回の記事にも出てきた CommandUI 型だ。CommnadUI 型はいろいろな所で使い回されているので、cabal-install の基本的な型のひとつだ。第2引数は、第1引数が flags 型、第2引数が String のリスト、戻り値が action の関数だ。flags と action はタイプ変数なので、特定の型を表している訳ではなく、 commandAddAction 関数は汎用に設計されているのだろう。戻り値は Commnad action になっているがこれが、この関数の使用目的だ。

Command action 型の定義を再掲する。

data Command action = Command String String ([String] -> CommandParse action)

第1のコンテナと、第2のコンテナの値が String 型で、第3のコンテナの値は String のリストを引数にとり、 CommnadParse action 型を戻り値にする関数だ。

CommandParse 型の定義も Distribution.Simple.Commnad モジュールで定義されている。定義ではコンテナの型が flags になっているが、これはタイプ変数だからどんな型でも使える。CommandParse 型もいろいろ使い回しできそうだ。

data CommandParse flags = CommandHelp (String -> String)
                        | CommandList [String]
                        | CommandErrors [String]
                        | CommandReadyToGo flags

commandParse 型については以前の記事で少し調べた。commandsRun 関数の処理の最終結果としての戻り値がこの commandParse 型の値だ。

commandAddAction 関数の CommandUI flag 型の第1引数の話に戻るが、その実例である、listCommand の定義は cabal-install のソースツリーの Distribution.Client.Setup モジュールの中にある。次がその定義だ。

-- ------------------------------------------------------------
-- * List flags
-- ------------------------------------------------------------

data ListFlags = ListFlags {
    listInstalled :: Flag Bool,
    listSimpleOutput :: Flag Bool,
    listVerbosity :: Flag Verbosity
  }

defaultListFlags :: ListFlags
defaultListFlags = ListFlags {
    listInstalled = Flag False,
    listSimpleOutput = Flag False,
    listVerbosity = toFlag normal
  }

listCommand  :: CommandUI ListFlags
listCommand = CommandUI {
    commandName         = "list",
    commandSynopsis     = "List packages matching a search string.",
    commandDescription  = Nothing,
    commandUsage        = usagePackages "list",
    commandDefaultFlags = defaultListFlags,
    commandOptions      = \_ -> [
        optionVerbosity listVerbosity (\v flags -> flags { listVerbosity = v })

        , option [] ["installed"]
            "Only print installed packages"
            listInstalled (\v flags -> flags { listInstalled = v })
            trueArg

        , option [] ["simple-output"]
            "Print in a easy-to-parse format"
            listSimpleOutput (\v flags -> flags { listSimpleOutput = v })
            trueArg

        ]
  }

instance Monoid ListFlags where
  mempty = defaultListFlags
  mappend a b = ListFlags {
    listInstalled = combine listInstalled,
    listSimpleOutput = combine listSimpleOutput,
    listVerbosity = combine listVerbosity
  }
    where combine field = field a `mappend` field b

ここでは、最初に ListFlags 型を定義している。そうしてデフォールトの ListFlags 型の値として、defaultListFlags を定義している。そうして listCommand は CommnadUI ListFlags 型の値として定義される。CommandUI の記事でも調べた通り、commandName, commandSynopsis, commandDescription, commandUsage, commandDefaultFlags のデータの型や意味は簡単に理解できる。commandOptions の読解が大変そうだが、今回は読解をパスする。おそらく CommnadsRun の定義の中で利用法が明らかになるだろうから、そのときにもう一度良く読めばいいのではないだろうか。ここでは listCommand が CommandUI ListFlags 型の値であるということが分かったという事でよしとしよう。

commandAddAcition 関数の第2引数の型は、(flags -> [String] -> action) という関数型になるが、listCommnad の場合は listAction だ。これは Main.hs に次のように定義されている。

listAction :: ListFlags -> [String] -> GlobalFlags -> IO ()
listAction listFlags extraArgs globalFlags = do
  let verbosity = fromFlag (listVerbosity listFlags)
  config <- loadConfig verbosity (globalConfigFile globalFlags) mempty
  let configFlags  = savedConfigureFlags config
      globalFlags' = savedGlobalFlags    config `mappend` globalFlags
  (comp, conf) <- configCompilerAux' configFlags
  list verbosity
       (configPackageDB' configFlags)
       (globalRepos globalFlags')
       comp
       conf
       listFlags
       extraArgs

commandAddAction の第2引数の型 (flags -> [String] -> action) と listAciton の型 ListFlags -> [String] -> GlobalFlags -> IO () が一致しないが、action はタイプ変数なので action = GlobalFlags -> IO () でよいのだろうか。cabal-install のコードでは、関数を汎用化するために関数の型にタイプ変数が頻繁に利用されている。見慣れない書き方なので戸惑う。

listAction でやっている事は、listFlags, extraArgs, GlobalFlags という設定情報から verbosity, (configPackageDB' configFlags), (globalRepos globalFlags'), comp, conf, listFlags, extraArgs などの文字列情報を取り出し、list 関数で表示する事のようだが、今回は細部には立ち入らない。

listCommand と listAction の概要が分かったので、commandAddAction 関数の働きを見てみる。

commandAddAction は汎用関数のようなのでおそらく Distribution.Simple.Command モジュールに定義されているのではないかと思って探したら、当たりだった。ソースは次のようになる。

commandAddAction :: CommandUI flags
                 -> (flags -> [String] -> action)
                 -> Command action
commandAddAction command action =
  Command (commandName command)
          (commandSynopsis command)
          (fmap (uncurry applyDefaultArgs)
         . commandParseArgs command False)

  where applyDefaultArgs mkflags args =
          let flags = mkflags (commandDefaultFlags command)
           in action flags args

commandAddAction 関数は引数の command, acition から情報を抽出し Command コンストラクタでラッピングしている。Command コンストラクタの第1コンテナは CommnadUI 型の command から commandName フィールドの文字列を抽出して納めている。第2コンテナは command の commandSynopsis フィールドの文字列を納める。

Command flag 型の第3のコンテナの型は ([String] -> CommandParse action) だが、command とaction の値を加工して作られる。その中心は次のコードだ。

(fmap (uncurry applyDefaultArgs) . commandParseArgs command False)

簡潔だが、分かりにくい。そこで、一番分かりやすそうな uncurry 関数から取り組んでみる。uncurry 関数は foo :: a -> b ->c のような2変数の関数を bar :: (a, b) -> c のようなペアの1変数関数に変換する関数だ。ghci で実験してみた。

Prelude> let foo x y = x + y
Prelude> uncurry foo (1,2)
3

foo は x と y の2変数関数だが、uncurry foo は (x, y) のペアの1変数関数になる。uncurry applyDefaultArgs の場合は、applyDefaultArgs の定義は where 句で行われており、その引数は mkflags と args だから、uncurry applyDefaultArgs は (mkflags, args) ペアの1引数関数になる。

applyDefaultArgs の定義は次のようになる。

  where applyDefaultArgs mkflags args =
          let flags = mkflags (commandDefaultFlags command)
           in action flags args

commandDeaultFlags は CommandUI 型のフィールド commandDefaultFlags のアクセサだ。従って commandDefaultFlagas commnad は command = listCommand の場合 defaultListFlags になる。したがって、listCommand の場合 flags = mkflags defaultListFlags となるはずだがこの mkflags はどこからくるのだろうか。コードをみるとそれは commandParseArgs の戻り値から得られると考えられる。

commnadParseArgs の型は次のようになる。

commandParseArgs :: CommandUI flags
                 -> Bool      -- ^ Is the command a global or subcommand?
                 -> [String]
                 -> CommandParse (flags -> flags, [String])

戻り値は CommandParse (flags -> flags, [String]) 型になる。これは CommandParse 型で (flags -> flags, [String]) 型のペアではない。だからそのままでは mkflags に利用する事ができないはずだが、fmap (uncurry applyDefaultArgs) のように fmap を利用して CommandParse のコンテナ内の (flags -> flags, [String]) ペアに直接 (uncurry applyDefaultArgs) を関数適用できる。CommandParse 型は Functor のインスタンスにしてあるので fmap を使う事ができるのだ。

commandParsArgs のコードは Distribution.Simple.Command で次のように記述されている。

commandParseArgs command global args =
  let options = addCommonFlags ParseArgs
              $ commandGetOpts ParseArgs command
      order | global    = GetOpt.RequireOrder
            | otherwise = GetOpt.Permute
  in case GetOpt.getOpt' order options args of
    (flags, _, _,  _)
      | any listFlag flags -> CommandList (commandListOptions command)
      | any helpFlag flags -> CommandHelp (commandHelp command)
      where listFlag (Left ListOptionsFlag) = True; listFlag _ = False
            helpFlag (Left HelpFlag)        = True; helpFlag _ = False
    (flags, opts, opts', [])
      | global || null opts' -> CommandReadyToGo (accum flags, mix opts opts')
      | otherwise            -> CommandErrors (unrecognised opts')
    (_, _, _, errs)          -> CommandErrors errs

  where -- Note: It is crucial to use reverse function composition here or to
        -- reverse the flags here as we want to process the flags left to right
        -- but data flow in function compsition is right to left.
        accum flags = foldr (flip (.)) id [ f | Right f <- flags ]
        unrecognised opts = [ "unrecognized option `" ++ opt ++ "'\n"
                            | opt <- opts ]
        -- For unrecognised global flags we put them in the position just after
        -- the command, if there is one. This gives us a chance to parse them
        -- as sub-command rather than global flags.
        mix []     ys = ys
        mix (x:xs) ys = x:ys++xs

結構複雑だが、ここでは commandParseArgs listCommand False の戻り値がどうなるかを知るだけでいい。そこで、コードの case 文の条件の所を見ると、any listFlagFlags の部分がどうやらそうらしい。この場合 commandParseArgs の戻り値は

CommandList (commandListOptions command)

となるようだ。commandListOptions 関数の定義も Distribution.Simple.Command モジュールにあり、その機能は CommandUI 型のデータの中のオプションに関するものを、オプションの文字列のリストにすることのようだ。

commandListOptions :: CommandUI flags -> [String]

したがって、 commandParseArgs listCommand False の場合、戻り値は CommandList [String] 型になる。コンテナのデータ型がペアではないが、そこは CommandParse 型の fmap 関数がうまくやってくれるのだろう。CommandParse 型を Functor クラスのインスタンスにした効果だ。

まだまだ解読しないといけない部分を省略したままだが、とりあえず冒頭にのべた commands の概要がつかめたので、次の記事では commandsRun の解読に取り組む。
[PR]
by tnomura9 | 2013-11-30 22:21 | Haskell | Comments(0)

年齢早見表

平成26年度 年齢早見表

明治 n 年: 147 - n 歳、1867 + n 年生まれ
大正 n 年: 103 - n 歳、1911 + n 年生まれ
昭和 n 年: 89 - n 歳、1925 + n 年生まれ
平成 n 年: 26 - n 歳、1988 + n 年生まれ
[PR]
by tnomura9 | 2013-11-27 11:01 | メモ | Comments(0)

恋するフォーチュンクッキー サマンサタバサグループ

元気が出る。

恋するフォーチュンクッキー サマンサタバサグループ

平和だなー。

AKB48 はあまり好きではなかったけれど、指原莉乃がセンターになってから少し興味が出てきた。
[PR]
by tnomura9 | 2013-11-24 20:16 | ボーカロイド | Comments(0)

globalCommand

前へ 目次 次へ

参照: cabal-install 関連のリンク

cabal-install のソースを読み始めて分かったのだが、main 関数を組み立てる部品になる関数を調べると、その関数を組み立てる部品になる関数があり、その関数を調べるとという感じで探索していかなければならない。

cabal-install くらいの大きいプログラムになると、自分がいま全体のどの部分を探索しているのかという事を知っていないと迷子になってしまう。

今まで調べた部分を階層的に表示すると次のようになる。

main @Main.hs
  mainWorker @Main.hs
    topHandler @Distribution.Simple.Utils
    commandsRun @Distribution.Simple.Command
      CommandParse @Distribution.Simple.Command
      CommandUI @Distribution.Simple.Commnad
      globalCommand @Distribution.Client.Setup

このように大きなプログラムになると、関数や値の定義がいろいろなファイルに分散しているので、それを探すのが一苦労だ。上の関数や値の中で、golobalCommnad がこの記事で扱おうと思っている値だ。

Main.hsmainWorker 関数の定義に使われていた commnadsRun の第1引数は globalCommand だ。

commandsRun globalCommand commands args

前回は globalCommnad の型の CommandUI flags について見てみた。今度は globalCommand そのものについて調べてみる。globalCommand の定義は Haskell の標準モジュールの中にはなく、cabal-install のソースツリーの /Distribution/Client/Setup.hs の中にある。

まず、CommandUI flags 型を再掲すると次のようになっている。

data CommandUI flags = CommandUI {
    commandName :: String,
    commandSynopsis :: String,
    commandUsage :: String -> String,
    commandDescription :: Maybe (String -> String),
    commandDefaultFlags :: flags,
    commandOptions :: ShowOrParseArgs -> [OptionField flags]
    }

各フィールドの commandName, commandSynopsis の値は単なる String 型だ。commandUsage の値は String 型を引数に取って String 型を返す関数。commandDescription の値は Maybe 型なので Nothing か、または、Just (Stirng -> String 型の関数) になる。commandDefaultFlags の型は flags になっている。この flags はタイプ変数だから、globalCommand の型を宣言するときに実際の型に置き換えられるはずだ。commandOpttions は ShowOrParseArgs 型の引数を取り [OptionFild flag] 型のリストを返す関数だ。各フィールドの値は変化に富んでいて、CommandUI 型がいろいろな情報を詰め込んでいることがわかる。

/Distribution/Client/Setup の globalCommand のコードは次のようになる。

globalCommand :: CommandUI GlobalFlags
globalCommand = CommandUI {
    commandName         = "",
    commandSynopsis     = "",
    commandUsage        = \_ ->
         "This program is the command line interface "
           ++ "to the Haskell Cabal infrastructure.\n"
      ++ "See http://www.haskell.org/cabal/ for more information.\n",
    commandDescription  = Just $ \pname ->
         "For more information about a command use:\n"
      ++ "  " ++ pname ++ " COMMAND --help\n\n"
      ++ "To install Cabal packages from hackage use:\n"
      ++ "  " ++ pname ++ " install foo [--dry-run]\n\n"
      ++ "Occasionally you need to update the list of available packages:\n"
      ++ "  " ++ pname ++ " update\n",
    commandDefaultFlags = defaultGlobalFlags,
    commandOptions      = \showOrParseArgs ->
      (case showOrParseArgs of ShowArgs -> take 2; ParseArgs -> id)
      [option ['V'] ["version"]
         "Print version information"
         globalVersion (\v flags -> flags { globalVersion = v })
         trueArg

      ,option [] ["numeric-version"]
         "Print just the version number"
         globalNumericVersion (\v flags -> flags { globalNumericVersion = v })
         trueArg

      ,option [] ["config-file"]
         "Set an alternate location for the config file"
         globalConfigFile (\v flags -> flags { globalConfigFile = v })
         (reqArgFlag "FILE")

      ,option [] ["remote-repo"]
         "The name and url for a remote repository"
         globalRemoteRepos (\v flags -> flags { globalRemoteRepos = v })
         (reqArg' "NAME:URL" (maybeToList . readRepo) (map showRepo))

      ,option [] ["remote-repo-cache"]
         "The location where downloads from all remote repos are cached"
         globalCacheDir (\v flags -> flags { globalCacheDir = v })
         (reqArgFlag "DIR")

      ,option [] ["local-repo"]
         "The location of a local repository"
         globalLocalRepos (\v flags -> flags { globalLocalRepos = v })
         (reqArg' "DIR" (\x -> [x]) id)

      ,option [] ["logs-dir"]
         "The location to put log files"
         globalLogsDir (\v flags -> flags { globalLogsDir = v })
         (reqArgFlag "DIR")

      ,option [] ["world-file"]
         "The location of the world file"
         globalWorldFile (\v flags -> flags { globalWorldFile = v })
         (reqArgFlag "FILE")
      ]
  }

上のコードで commandName, commandSynopsis フィールドの値は空文字列 "" だ。commandUsage フィールドの値は String 型を引数に取り String 型の値を返す関数だが、引数がワイルドカードになっているので引数がどんな値でも -> 以下の文字列が帰ってくる。つまり、

(commandUsage globalCommnad) "" の値を putStrLn すると、

This program is the command line interface to the Haskell Cabal infrastructure.
See http://www.haskell.org/cabal/ for more information.

になるはずだ。

commandDescription フィールドの値は、ラムダ記法で記述された関数 \pname -> ... を Just コンストラクタでラッピングしている。したがって文章の中の pname に相当する部分は置き換えることができる。たとえば次のような操作で、

putStrLn $ (fromJust (commandDescription globalCommand)) "cabal"

次のような文章を表示させることができるはずだ。

For more information about a command use:
 cabal "COMMAND --help
To install Cabal packages from hackage use:
 cabal install foo [--dry-run]

Occasionally you need to update the list of available packages:
 cabal update

commandDefaultFlags フィールドの値は defaultGlobalFlags だ。defaultGlobalFlags の定義も Distribution/Client/Setup.hs に記述されている。そこでは、まず GlobalFlags 代数的データ型が定義され、次に GlobalFlags 型の値として defaultGlobalFlags が定義されている。

data GlobalFlags = GlobalFlags {
    globalVersion        :: Flag Bool,
    globalNumericVersion :: Flag Bool,
    globalConfigFile     :: Flag FilePath,
    globalRemoteRepos    :: [RemoteRepo],     -- ^ Available Hackage servers.
    globalCacheDir       :: Flag FilePath,
    globalLocalRepos     :: [FilePath],
    globalLogsDir        :: Flag FilePath,
    globalWorldFile      :: Flag FilePath
  }

defaultGlobalFlags :: GlobalFlags
defaultGlobalFlags  = GlobalFlags {
    globalVersion        = Flag False,
    globalNumericVersion = Flag False,
    globalConfigFile     = mempty,
    globalRemoteRepos    = [],
    globalCacheDir       = mempty,
    globalLocalRepos     = mempty,
    globalLogsDir        = mempty,
    globalWorldFile      = mempty
  }

GlogalFlags 型の globalVersion などのフィールドの値は Flag 型だが、Flag 型は GHC の標準ライブラリの Distribution.Simple.Setup モジュールに記載されていて次のように定義されている。

data Flag a = Flag a | NoFlag deriving (Show, Read, Eq)

Maybe 型と似ていて、Flag コンストラクタが Just に相当し、NoFlag コンストラクタが Nothing に相当する。Maybe 型でも良かったのではないかと思うが、次のように Flag 型は色々なクラスのインスタンスに宣言されているので、Maybe 型とは用途が違うのだろう。

Flag 型は、Show, Read, Eq, Functor, Monoid, Bounded, Enum などのクラスのインスタンスになっているのでそれらの多相関数が使う事ができるが、上のコードを読むには Monoid クラスのインスタンスであることを知っていれば足りる。Flag 型の Monoid クラスでの実装は次のようになっている。

instance Monoid (Flag a) where
  mempty = NoFlag
  _ `mappend` f@(Flag _) = f
  f `mappend` NoFlag    = f

mempty は NoFlag だ。mappend では後でアペンドされたフラグで前のフラグが置き換えられる。f@(Flag _) というみなれないパターンはアズ・パターン (as-patter) で f がパターン (Flag _) と同じものである事を表している。as-pattern を ghci で試してみた。

Prelude> :set +m
Prelude> let
Prelude| test f@("hello") = f
Prelude| test _ = "not match"
Prelude|
Prelude> test "hello"
"hello"
Prelude> test "hi"
"not match"

globalDefaultFlags は DefaultFlags 型だが、その定義を見ると各フィールドの値は全て空だということが分かる。

commandOptions の値は冒頭で述べた通り ShowOrParseArgs -> [OptionField flags] 型の関数だ。ShowOrParseArgs の型の定義は、標準ライブラリの Distribution.Simple.Command で定義されており、ShowArgs と ParseArgs の2つのコンストラクタからなっている。従って commandOptions の値は ShowOrParseArgs の値次第で切り替えられることになる。実際、commandOptions のコードの冒頭の部分は次のようになっているので、

    commandOptions      = \showOrParseArgs ->
      (case showOrParseArgs of ShowArgs -> take 2; ParseArgs -> id)

与えられる引数が ShowArgs のときは、冒頭部分に続くリストの最初の2つの要素からなるリストが返され、ParseArgs の場合は、全てのリストが返る。このリストだが、型が [OptionField flags] なので、要素が OptionField 型のリストだ。

OptionField 型の定義は、標準モジュールの Distribution.Simple.Command モジュールに記述されている。コメントにあるように、コマンドラインやコンフィギュレーション・ファイルから指定されたオプションのデータを保持するためのデータ型だ。

-- | We usually have a datatype for storing configuration values, where
--   every field stores a configuration option, and the user sets
--   the value either via command line flags or a configuration file.
--   An individual OptionField models such a field, and we usually
--   build a list of options associated to a configuration datatype.
data OptionField a = OptionField {
  optionName        :: Name,
  optionDescr       :: [OptDescr a] }

-- | An OptionField takes one or more OptDescrs, describing the command line interface for the field.
data OptDescr a  = ReqArg Description OptFlags ArgPlaceHolder (ReadE (a->a))         (a -> [String])
                 | OptArg Description OptFlags ArgPlaceHolder (ReadE (a->a)) (a->a)  (a -> [Maybe String])
                 | ChoiceOpt [(Description, OptFlags, a->a, a -> Bool)]
                 | BoolOpt Description OptFlags{-True-} OptFlags{-False-} (Bool -> a -> a) (a-> Maybe Bool)

-- | Short command line option strings
type SFlags   = [Char]
-- | Long command line option strings
type LFlags   = [String]
type OptFlags = (SFlags,LFlags)
type ArgPlaceHolder = String

上の定義で SFlags は short flags のリストで、LFlags は long flags のリストだろう。

globalCommand のコードを読むと OptionField 型のデータは直接定義するのではなく option 関数を利用して作るようだ。options 関数の定義もやはり Distribution.Simple.Command モジュールで定義されておりそのコードは次のようになっている。

-- | Create an option taking a single OptDescr.
-- No explicit Name is given for the Option, the name is the first LFlag given.
option :: SFlags -> LFlags -> Description -> get -> set -> MkOptDescr get set a -> OptionField a
option sf lf@(n:_) d get set arg = OptionField n [arg sf lf d get set]
option _ _ _ _ _ _ = error "Distribution.command.option: An OptionField must have at least one LFlag"

option 関数は単に引数を OptionField 型にラッピングする働きをしているだけのようだ。ただし、lf@(n:_) となっているから long flags のリストから先頭の要素を取り出している。

options で作成された OptionField 型のデータの optionName フィールドの値は n で optionDescr フィールドの値は [arg sf lf d get st] という [OptDescr a] 型のリストになる。arg sf lf d get st はリストの要素を並べたものではなく、arg 関数を sf lf d get st に適用している。

options 関数の実際の使い方は golobalCommand のコードを見れば分かるはずだが、

      [option ['V'] ["version"]
         "Print version information"
         globalVersion (\v flags -> flags { globalVersion = v })
         trueArg

引数の数が合わない。また、option 関数の型を再掲すると、

option :: SFlags -> LFlags -> Description -> get -> set -> MkOptDescr get set a -> OptionField a

の意味が分からない。option 関数の型シグネチャに get, set など型変数らしきものが現れているのは初めて見た。MkOptDesc は標準モジュールの Distribution.Simple.Command で type 宣言されている。関数型の別名のようだ。

type MkOptDescr get set a = SFlags -> LFlags -> Description -> get -> set -> OptDescr a

OptionField についてはこの記事で既に述べた。

globalVersion は GlobalFlags 型のフィールド名 (フィールド名はそのフィールドへのアクセサ関数と同名) だ。また、trueArg は標準ライブラリ Distribution.Simple.Setup の GetOpt Utils セクションで定義されている。

trueArg, falseArg :: SFlags -> LFlags -> Description -> (b -> Flag Bool) ->
                     (Flag Bool -> (b -> b)) -> OptDescr b
trueArg  = noArg (Flag True)
falseArg = noArg (Flag False)

noArg は標準モジュールの Distribution.Simple.Command モジュールの OptDescr smart constructors セクションで記述されていて、コードは次のようになる。

noArg :: (Eq b, Monoid b) => b -> MkOptDescr (a -> b) (b -> a -> a) a
noArg flag sf lf d = choiceOpt [(flag, (sf,lf), d)] sf lf d

どうやら Descr a 型の値でコンストラクタが choiceOpt のデータを作成するための関数のようだ。

option 関数の型のシグネチャーに型変数が現れているが、こういうコードは初めて見たので少し調べる必要がある。

type sgnature の中に type variable が現れるのは、関数の値が関数になる場合は可能なようだ。ghci で次のような実験をしてみたら、ちゃんと動いた。

Prelude> let
Prelude| test2 :: Int -> [a] -> [a]
Prelude| test2 x = take x
Prelude|
Prelude> test2 2 [1,2,3]
[1,2]

option 関数の場合も、SFlags = ['V'], LFlags = ["version"], Descr = "Print version information" までの対応関係はわかるのだが、get -> set -> MkOptDescr get set a と globalVersion (\v flags -> flags { globalVersion = v }) trueArg との対応付けが分からない。

しかし、get = glovalVersion, set = (¥v flags -> flags {glovalVersion = v}), MkOptDesr get set a = trueArg という対応付けが可能なら

tureArg sf lf d get set で Descr a 型の値が作られるのが分かる気がする。get や set などの型変数も関数の型のシグネチャーに普通に使えることがあるという事だ。ghci で次のような実験をしてみたら納得できた。

Prelude> :set +m
Prelude> data Foo a b = Foo a b deriving Show
Prelude> let
Prelude| bar :: a -> b -> Foo a b
Prelude| bar x y = Foo x y
Prelude|
Prelude> bar 1 "hello"
Foo 1 "hello"

globalCommnadcommandOptions の構成はこのように非常に複雑だが、その意味は cabal-install を使ってみればすぐ分かる。commandOptions の [OptionFild flag] 型のリスト の最初の要素は次のようになるが、

      option ['V'] ["version"]
         "Print version information"
         globalVersion (\v flags -> flags { globalVersion = v })
         trueArg

['V'] は cabal-install の short option を表している。コマンドラインで cabal -V と入力すると次のような結果になる。

$ cabal -V
cabal-install version 1.16.0.2
using version 1.16.0 of the Cabal library

また ["version"] は long option を表している。

$ cabal --version
cabal-install version 1.16.0.2
using version 1.16.0 of the Cabal library

このように commandOptions フィールドの [OptionFild flag] のリストにはそのコマンドのオプションに関する情報が納められていることがわかる。
[PR]
by tnomura9 | 2013-11-17 18:35 | Haskell | Comments(0)

スーザン・ボイル

映画のクライマックスのようだ。感動した。

【HD】スーザン・ボイル 〜夢をつかんだ奇跡の歌声〜
[PR]
by tnomura9 | 2013-11-16 08:10 | ボーカロイド | Comments(0)

CommandUI

前へ 目次 次へ

参照: cabal-install 関連のリンク

Main.hs の mainWorker 関数の定義に使われていた commnadsRun の第1引数の globalCommand の型はCommandUI flags だ。

commandsRun globalCommand commands args

CommnadUI flags 型の定義は Description.Simple.Command モジュールにあり、次のようになっている。

data CommandUI flags = CommandUI {
    -- | The name of the command as it would be entered on the command line.
    -- For example @\"build\"@.
    commandName        :: String,
    -- | A short, one line description of the command to use in help texts.
    commandSynopsis :: String,
    -- | The useage line summary for this command
    commandUsage    :: String -> String,
    -- | Additional explanation of the command to use in help texts.
    commandDescription :: Maybe (String -> String),
    -- | Initial \/ empty flags
    commandDefaultFlags :: flags,
    -- | All the Option fields for this command
    commandOptions     :: ShowOrParseArgs -> [OptionField flags]
  }

CommandUI flag 型は名前付きフィールドで定義されている。フィールド名の name はコマンドの名前(例えば build)を納めている。commandSynopsis はコマンドの使用法を1行で説明したもの。commandUsage はヘルプで表示するコマンドの詳細な説明だが、データ型が String -> String の関数型になっている。これは推測だが、使用法の説明の String が長過ぎたときに整形するなどの使い方があるのではないだろうか。commandDescription フィールドの型は Maybe (String -> String) で commandUsage の付加的な説明。Maybe 型になっているので付加的情報がない (Nothing) も想定している。commandDefaultFlags はフラグの初期値または empty flags を納める。このコマンドの全ての Option 用のフィールド commandOptions は。ShowOrParseArgs -> [OptionFild flags] 型なので SowOrParseArgs 型のデータから、[OptionField flags] 型への関数になっている。ShowOrParseArgs のデータ型は次のようになっているので、

data ShowOrParseArgs = ShowArgs | ParseArgs

showOrParseArgs の値でオプションに対する処理を切り替えるのだろう。

次の行は OptionField のデータ型の定義になっている。まず次のように Name と Description という String 型の別名を作る。

type Name        = String
type Description = String

-- | We usually have a datatype for storing configuration values, where
--   every field stores a configuration option, and the user sets
--   the value either via command line flags or a configuration file.
--   An individual OptionField models such a field, and we usually
--   build a list of options associated to a configuration datatype.

コマンドを実行する際には、オプションを管理するデータ型を利用することが多い。このデータ型のフィールドには configuration オプションや、ユーザの設定を納めている。これらの値は、コマンドラインからのフラグや、設定ファイルを通じて指示する事ができる。個々の OptionField はそのようなフィールドを設計している。一般的にはそのようなオプションはリストを形成し、コマンド動作の設定のためのデータベースになっている。

data OptionField a = OptionField {
  optionName        :: Name,
  optionDescr       :: [OptDescr a] }

-- | An OptionField takes one or more OptDescrs, describing the command line interface for the field.

OptionField は1個か数個の OptDecrs をとる。これは、このフィールドのコマンドラインインターフェースの値を保持している。

data OptDescr a  = ReqArg Description OptFlags ArgPlaceHolder (ReadE (a->a))         (a -> [String])
                 | OptArg Description OptFlags ArgPlaceHolder (ReadE (a->a)) (a->a)  (a -> [Maybe String])
                 | ChoiceOpt [(Description, OptFlags, a->a, a -> Bool)]
                 | BoolOpt Description OptFlags{-True-} OptFlags{-False-} (Bool -> a -> a) (a-> Maybe Bool)

OptDescr a の各コンストラクタ RegArg, OptArg, ChoiceOpt, BoolOpt はオプションの種類を表している。また、それぞれのコンストラクタのパラメータ Description OptFlags ArgPlaceHolder などは各オプションのパラメータの型だろう。最後の2つのパラメータ (ReadE (a->a)) (a -> [String]) はコマンドやオプションの動作と関係しているのだろうがここではその意味が分からない。

OptDescr のパラメータの型のうち、Description は String 型の別名だ。また、OptFlags, … は次のように type  宣言された、既存の型の別名だ。

-- | Short command line option strings
type SFlags   = [Char]
-- | Long command line option strings
type LFlags   = [String]
type OptFlags = (SFlags,LFlags)
type ArgPlaceHolder = String

このように、コマンド関連の情報は CommandUI flags 型に、コマンドのオプション関連の情報は OptionField a 型に保持されている。複雑な構造だが、cabal-install のコマンドとそのオプションに全て対応するためにはこういう複雑な構造が必要になってくるのだろう。

追記

OptionField a 型の型変数 a はコマンドのオプションの状態を表すフラグセットの型を表している。例えば、Distribution.Simple.Setup モジュールの globalCommnad には globalCommand の動作をコントロールするためのフラグセット GlobalFlags がある。次のようにすれば ghci で GlobalFlags の構成を知ることができる。

Prelude> :set prompt "ghci> "
ghci> import Distribution.Simple.Command
ghci> import Distribution.Simple.Setup
ghci> import Distribution.ReadE
ghci> import Data.Monoid

ghci> :info GlobalFlags
data GlobalFlags
  = GlobalFlags {globalVersion :: Flag Bool,
                 globalNumericVersion :: Flag Bool}
        -- Defined in `Distribution.Simple.Setup'
instance Monoid GlobalFlags
  -- Defined in `Distribution.Simple.Setup'

GlobalFlags には globalVerion と globalNumericVersion という2つのフィールドがあり、それぞれ Flag Bool 型の値を収めている。OptDescr a 型のパラメータの最後の2つは、このフラグセットのフィールドの値を操作する関数が収められている。最後から2つ目のパラメータがフラグセットの特定のフィールドに値を設定する関数で、最後のパラメータはフラグセットの特定のフィールドの値を取り出す関数だ。

ghci> :info OptDescr
data OptDescr a
  = ReqArg Description
           OptFlags
           ArgPlaceHolder
           (ReadE (a -> a))
           (a -> [String])
  | OptArg Description
           OptFlags
           ArgPlaceHolder
           (ReadE (a -> a))
           (a -> a)
           (a -> [Maybe String])
  | ChoiceOpt [(Description, OptFlags, a -> a, a -> Bool)]
  | BoolOpt Description
            OptFlags
            OptFlags
            (Bool -> a -> a)
            (a -> Maybe Bool)
        -- Defined in `Distribution.Simple.Command'

このように OptDescr a 型のデータを利用すれば、フラグセット a のフィールドの値を操作できることが分かる。そうして、例えば globalCommand における GlobalFlags のように、このフラグセットのフラグの値でコマンドの動作をコントロールすることになる。
[PR]
by tnomura9 | 2013-11-11 02:05 | Haskell | Comments(0)

CommandParse

前へ 目次 次へ

参照(command-innstall 関連のリンク

Main.hscommandWorker の中での commandsRun 関数の使い方は次のようになっている。

mainWorker args = topHandler $
  case commandsRun globalCommand commands args of
    CommandHelp help -> printGlobalHelp help
    CommandList opts -> printOptionsList opts
    ...

つまり、commandsRun の戻値のパターンによってその後の関数の振る舞いを分岐させている。したがって、commandsRun の値はコマンド・ライン引数をパースして検出したコマンドの種類を表していると考えられる。

commandsRun の定義は Distribution.Simple.Command モジュールの中にあり、その型は次のようになる。

commandsRun :: CommandUI a -> [Command action] -> [String] -> CommandParse (a, CommandParse action)

したがって、commandsRun 関数の戻値は CommnadParse (a, CommandParse action) 型だ。

CommandParse 型の定義はやはり Distribution.Simple.Command モジュールにあり、次のように data 宣言されている。

data CommandParse flags = CommandHelp (String -> String)
  | CommandList [String]
  | CommandErrors [String]
  | CommandReadyToGo flags
instance Functor CommandParse where
  fmap _ (CommandHelp help) = CommandHelp help
  fmap _ (CommandList opts) = CommandList opts
  fmap _ (CommandErrors errs) = CommandErrors errs
  fmap f (CommandReadyToGo flags) = CommandReadyToGo (f flags)

CommandParse flags の flags は単なる型変数で Maybe a の a などと同じ意味しかない、つまりどのような型も flags の位置に使えるということだ。型変数 flags は定義の右辺では CommandReadyToGo コンストラクタのパラメータに使われている。(解読がだいぶ進んでから分かった事だが、flags は install などのコマンドの動作を設定するためのフラグセットを表しているようだ。コマンドのフラグセットについては後の方の解読で頻繁に解析する。)

代数的データ型 CommandParse flags は、Distribution.Simple.Command モジュールをインポートすれば ghci 上で使うことができるが、CommandParse 型は Show クラスのインスタンスではないので、その内容を表示できない。しかし、次のように showCP 関数を定義してしまえば、簡単に CommandParse 型の内容を表示させることができる。

Prelude> import Distribution.Simple.Command
let {showCP (CommandHelp help) = "CommnadHelp " ++ show (help "foo"); showCP (CommandList opts) = "CommandList " ++ show opts; showCP (CommandErrors errs) = "CommandErrors " ++ show errs; showCP (CommandReadyToGo flags) = "CommnadReadyToGo " ++ show flags}
Prelude Distribution.Simple.Command> putStrLn $ showCP (CommandList ["foo", "bar"])
CommandList ["foo","bar"]

これを見ると CommandParse flag 型は、コマンド・ラインのパースを行うだけでなく、それぞれのコマンドを実行するためのパラメータを一緒に返してくれる事が分かる。つまり、commandsRun を実行すると、3番目の引数 args をパースして、args で指定されたコマンドの種類(たとえば CommandList など)を、それを実行するためのパラメータ(["foo", "bar"]) などと一緒に返すことがわかる。

CommnadParse 型についてはもう一つ注意点がある。それは CommandParse 型が Functor クラスのインスタンスであるということだ。上のソースコードのinstance 宣言以下の部分が Functor クラスの(多形)関数 fmap の実装を記述している。

Functor クラスというと難しく聞こえるが、要するに fmap 関数をオーバーロードして使えるようにしているだけだ。fmap 関数が使える Functor クラスの Haskell 標準のデータ型は Maybe a 型や List 型がある。fmap の働きは map 関数に似ている。map 関数は第1引数の関数を第2引数のリストの要素に関数適用したリストを返すが、

Prelude Distribution.Simple.Command> map (*2) [1,2,3]
[2,4,6]

fmap は map を一般化して、第2引数が Functor クラスのインスタンスなら List 型でなくても上の操作ができるようにしたものだ。

Prelude Distribution.Simple.Command> fmap (*2) (Just 3)
Just 6

CommandParse 型の fmap の動作は次のようになる。

Prelude Distribution.Simple.Command> putStrLn $ showCP $ fmap (\x -> "hello, " ++ x) (CommandReadyToGo "world")
CommnadReadyToGo "hello, world"

以上のことをまとめると CommandParse 型は、コマンドの種類をコンストラクタ (例えば CommnadList ) で表し、そのコマンドのパラメータをコンストラクタのコンテナに保持しているという事が分かる。
[PR]
by tnomura9 | 2013-11-08 03:00 | Haskell | Comments(0)

Superfly

疾走感が気持ちいい。なかなかの歌い手。日本の音楽も頑張っている。

Superfly - Bi-Li-Li Emotion (ビリリエモーション)

Superfly - 愛をこめて花束を

Superfly - 輝く月のように
[PR]
by tnomura9 | 2013-11-05 00:14 | ボーカロイド | Comments(0)

Cabal User Guide 5 (Building and installing packages)

前へ 目次 次へ

Cabal User Guide > Building and installing packages

setup build

パッケージのインストールを準備するために必要なプリプロセッシングやコンパイルをする。

このコマンドにはつぎのようなオプションがある。

–prog-options=options, –prog-option=option

これらのオプションはほとんどが configure ステップのものと同じである。configure ステップで指定されたオプションと違って、ビルド・ステップで使われるオプションはそのステップ限りのものだ。ビルド・ステップで指定されるオプションはそれに加えて、configure ステップで設定されたオプションを上書きしない。

setup haddock

パッケージの文書を haddock を使ってビルドする。デフォールトでは公開されるモジュールに関する文書のみが作成される。(しかし、下記の --executables と --internal フラグを使えばその限りではない。)

このコマンドにはつぎのようなオプションがある。

--hoogle

dist/doc/html/pkgid.txt ファイルを生成する。このファイルは Hoogle によって検索用のデータベースに変換される。このオプションは haddock を --hoogle フラグで起動するのと同じ動作をする。

--html-location=url

パッケージに必須のHTML 文書の場所に関するテンプレートを指定する。個々のパッケージの文書を納める位置を得る(listing 参照)ために、テンプレートに記述されている URL の置き換えが行われる。この処理は発生させた文書にハイパーリンクを設定するのに利用される。例えば、次のようなコマンドは Hackage のページへのリンクを生成する。

setup haddock –html-location=‘http://hackage.haskell.org/packages/archive/$pkg/latest/doc/html’

引数はシェルによる置き換えを防ぐため引用符で囲む必要がある。このオプションが省略された場合、個々のパッケージの位置の情報はパッケージツール (ghc-pkg) を利用して取得される。

--executables

実行可能プログラムから利用される全てのモジュールに関して haddock を使って文書を作成する。デフォールトでは haddock は export されたモジュールに関してのみ文書を作成する。

--internal

全てのモジュールに対して haddock による文書を作成する。この場合、export されていないシンボルに対しても文書が作成される。

--css=path

引数のパスは CSS ファイルのパスを指定する。パスの情報は haddock に渡され、生成する HTML 文書のスタイルをきめる。このオプションは haddock のデフォールトの CSS を上書きするときにのみ必要である。

--hyperlink-source

haddock の文書を HsColour と統合して生成する。最初に、HsColour が起動されカラー化されたコードを生成する。次に haddock が起動して HTML 文書を生成する。HTML 文書の項目はカラー化されたコードの定義へとリンクされる。

--hscolour-css=path

引数のパスは CSS ファイルのパスを指定する。これは、 HsColour に次のように渡される。

runhaskell Setup.hs hscolour –css=path

setup hscolour

HsColour を使ってカラー化されたコードの HTML 文書を生成する。export されたモジュールのカラー化コードは /dist/doc/html/pkgid/src に置かれる。

このコマンドでは次のオプションが利用できる。

--executables

HsColour を実行プログラムに対しても適用する。カラー化されたコードは dist/doc/html/pkgid/executable/src ディレクトリに入れられる。

--css=path

生成された HTML ファイルに対し path で指定した CSS を使う。CSS ファイルはカラー化されたコードに使う色の定義をしている。この動作は指定された CSSファイルを hscolour.css にリネームしてコピーすることで実現させるので、生成された HTML ファイルにリンクを作成するわけではないことに注意が必要。

setup install

パッケージのコンパイル後のファイルを、インストール・ロケーションにコピーし、ライブラリの場合はコンパイラにパスを登録する。ライブラリは登録されるとプログラムから使うごとができるようになる。

コンパイルされたファイルのインストール場所は、setup configure のオプションで決められる。

このコマンドでは次のオプションが利用できる。

--global

このパッケージをシステム全体のデータベースに登録する。これはデフォールトの動作で、configure コマンドで --user オプションが使われないかぎり、システム・データベースへ登録されることになる。

--user

パッケージがユーザのローカル・パッケージ・データベースに登録される。このオプションは、configure command が --user オプションで実行された場合はデフォールトになる。

setup copy

ファイルをコピーするがパッケージをデータベースに登録しない。このコマンドは主にバイナリ・パッケージを作るときに使われる。

このコマンドでは次のオプションが利用できる。

--destdir=path

インストールするファイルを置くディレクトリを path で指定する。このオプションが使われていない場合、root ディレクトリが使われる。

setup register

パッケージをコンパイラに登録する。つまり、プログラムから利用可能なモジュールを作成する。このコマンドは、ライブラリ・パッケージにのみ有効だ。この動作は install コマンドに組み入れられているので注意が必要だ。このオプション個別に使うのは、バイナリ・パッケージをインストールしたあとの処理をするときだ。

このコマンドでは以下のオプションが利用可能だ。

--global

パッケージをシステム・データベースに登録する。(デフォールト)

--user

パッケージをユーザのローカル・データベースに登録する。

--gen-script

パッケージを register する代わりに、register の動作を行うコマンドを含むスクリプトを生成する。Unix ではこのスクリプトは register.sh である。Windows では register.bat になる。このスクリプトは binary bundle の tarball に含まれていることがおおい。bundle をターゲットのシステムで解凍した後、このスクリプトを起動するとパッケージの register とインストールができる。

--gen-pkg-config[=path]

パッケージをインストールする代わりに、package registration file を作成する。このオプションはコンパイラが package registration file をサポートしている場合にのみ有効だ。そのようなコンパイラは、今のところ GHC のみである。このようなファイルはコンパイラのパッケージを register する機能のために使われる。可能限りこのオプションの代わりに --gen-script オプションを使った方が良い。そのほうが、多くの Haskell 実装に対してポータブルなパッケージにする事ができる。パラメータの path は追加選択的なもので、特別の出力ファイルを生成する場合に使用する。それ以外は、デフォールトで生成されるファイルの名前はパッケージ名、バージョン、 .conf 拡張子からなっている。

--inplace

パッケージをビルド・ツリーから直接使えるように register する。この場合バイナリファイルのインストールを行う必要はない。この機能はテストの際に有用だ。それはソースを変更してもインストールをやり直す必要がないからだ。したがって、そのままリコンパイルしてテストすることができる。

このフラグは build-tree-local のパッケージ・データベースは生成しない。しかし、パッケージをユーザやグローバルのデータベースに register する。

しかしながら、このオプションには注意点がある。このオプションは (現在の所) GHC でしか働かない。またパッケージのプログラムが補助的なファイルに依存していない場合にのみ有効だ。つまり、プログラムが基本的な Haskell ライブラリに依存しているだけなら有効だ。

setup unregister

パッケージのコンパイラへの登録を抹消する。

このコマンドでは以下のオプションが利用可能である。

--global

パッケージをシステム・データベースから削除する。(デフォールト)

--user

パッケージをユーザのローカル・パッケージ・データベースから削除する。

--gen-script

パッケージの登録抹消をする代わりに、登録抹消を実行するスクリプトを生成する。Unix ではこのファイルは unregister.sh で、Windows では unregister.bat だ。このスクリプトは binary bundle に含まれている場合がある。ターゲットシステムでパッケージの登録抹消を実行するためだ。

setup clean

configure, build, haddock, register, ungegister ステップの間に生成されたローカル・ファイルを削除する。また、extra-temp-files フィールドに記述されていた、ファイルやディレクトリも削除する。

このコマンドでは以下のオプションが利用可能である。

--save-configure or -s

configure 情報を残す、こうすることでビルドを繰り返す際に configure ステップを省略できる。

setup test

パッケージ設定ファイル (.cabal ファイル) に記述されているテスト・スーツを実行する。後述するフラグは別として、Cabale は1個以上のテスト・スーツの名前を、コマンドラインの test コマンドの後に指定する事ができる。テスト・スーツの名前が指定された場合、Cabal は名前を指定されたテスト・スーツのみを実行する。それ以外は、Cabal はパッケージ設定ファイルに記述された全てのテストを実行する。

--builddir=dir

Cabal が生成した build file を置くディレクトリを指定する (デフォールト: dist)。テスト結果のログは test サブディレクトリに置かれる。

--human-log=path

人間が読めるテスト・ログのためのテンプレートを指定する。path は dist/test ディレクトリに対する相対パス名を指定する。デフォールトでは、ログは $pkgid-$test-sute.log テンプレートによって命名される。そのため、個々のテスト・スーツはそれぞれの人間に可読なログ・ファイルに記録される。テンプレートに使える変数は、$pkgid, $compiler, $os, $arch, $test-sute, および $result だ。

--machine-log=path

機械判読のログのパスだ。path は dist/test からの相対パスだ。デフォールトのテンプレートは $pkgid.log だ。テンプレートの変数としては、$pkgid, $compiler, $os, $arch および $result を使う事ができる。

--show-details=filter

filter によって個々のテスト・ケースの結果を端末に表示するかどうかを決める。filter には always (いつも表示する)、never (いつも表示しない)、および failures (テスト・スーツで失敗したケースだけを表示する)がある。

--test-options=options

テストの実行ファイルに付加的なオプションを与える。

--test-option=option

テストの実行ファイルに付加的なオプションを与える。このオプション指定では単一のオプションを指定できるだけなので、オプションに引用符で囲まれた空白区切りのオプションリストを使う必要がない。また、オプションを空白文字で区切ることはできない。

setup sdist

システムやコンパイラーによらないソースの配布を package-version.tar.gz 圧縮ファイルに作成する。作成されたファイルは dist サブディレクトリに置かれる。パッケージ制作者はそのファイルを配布できる。パッケージファイルが解凍されたときは、このセクションのリストでのべたコマンドが利用できる。

この配布用ファイルに含まれるのは、package description file (.cabal), setup スクリプト, package description file に記述されたモジュールのソース・ファイル, それから、.cabal ファイルの各フィールド、すなはち、license-file, main-is, c-sources, data-files, extra-sours-files および extra-html-files フィールドで指定されるファイル群だ。

このコマンドでは次のようなオプションが使用可能だ。

--snapshot

パッケージファイルの作成日 (YYYYMMDD の形式) をソースパッケージのバージョン番号に付加する。オリジナルのパッケージは影響をうけない。
[PR]
by tnomura9 | 2013-11-04 09:05 | Haskell | Comments(0)

Cabal User Guide 4 (Building and installing packages)

前へ 目次 次へ

Cabal User Guide > Building and installing packages

Prefix-independence

Windows や Hugs (どんなシステムでも) では実行中のプログラムのパス名を取得することができる。このことは、絶対パスによらないリロケータブルなパッケージをインストールすることができるということを意味している。実行ファイルは、そのブログラムに付随するファイルを自分の置かれているパスを検索することで見つけることができる。$bindir にたいする相対パスを知っていればいいからだ。Prefix-independence は特に有用だ。それはユーザーが実行ファイルのインストール場所(つまり、$prefix) をインストール時に選べるということを意味している。この場合、バイナリの実行ファイルのためにビルド時にパスを新たに作成する必要がない。

これを可能にするためには Windows の実行ファイルでは全ての $bindir, $libdir, $datadir, $libexecdir の値が $prefix で始まる必要がある。そうでない場合は、コンパイルされた実行ファイルのために予め絶対パスのディレクトリを作成しておく必要がある。

アプリケーションの場合は prefix-independent なリロケータブルプログラムを作るのに特別なことをする必要はない。そのアプリケーションの中で getDataFileName やその他のリロケータブルプログラムを使うための関数を利用していれば、現在の実行ファイルのディレクトリにたいしての相対パスで必要なファイルにアクセスできるからだ。

ライブラリについては現在のところ prefix-independent ではない。なぜなら、実行ファイルのシステムでの位置がライブラリと無関係の時はライブラリは実行ファイルにリンクされるからだ。

Controlling Flag Assignments

Flag assignments (see the resolution of conditions and flags) can be controlled with the followingcommand line options.

フラグの設定は(詳細は resolution of conditions and flags 参照)次のコマンドラインオプションでできる。

-f flagname or -f -flagname

特定のフラグを true または false (フラグ名の先頭に - をつける) に設定する。設定が重複した場合は後の設定で上書きされる。つまり、-fdebug -f-debug と入力された場合 -f-debut と同じことになる。

--flags=flagspecs

Same as -f, but allows specifying multiple flag assignments at once. The parameter is a space-separated list of flag names (to force a flag to true), optionally preceded by a - (to force a flag to false). For example, --flags="debug -feature1 feature2" is equivalent to -fdebug -f-feature1 -ffeature2.

-f と同じ意味だが、複数のフラグを一度に設定できる。パラメータは空白文字で区切られたフラグ名のリストだ。フラグ名だけのときは true に、フラグ名の先頭に - がついている場合は false に設定される。たとえば、--flags="debug -feature1 feature2" は -fdebug -f-feature1 -ffeature2 と同じ意味になる。

Building Test Suites

--enable-tests

パッケージの description file に記述されたテスト・スーツをソースのビルド・ステージの際に一緒にビルドする。テスト・スーツが要求する依存関係をチェックしておく必要がある。もし、パッケージがこのオプションで configure されていたときは、パッケージがビルドされた後で、テスト・コマンドでテスト・スーツを起動することができる。

--disable-tests

デフォールトではこのフラグが true になっている。ビルド・ステージでテスト・スーツのビルドを行わない。テスト・スーツでだけ必要な依存関係に関するチェックは行われない。パッケージを reconfigure しない限り、テスト・コマンドでテストを実行することはできない。

Miscellaneous options

--user

ユーザーごとのインストールをする。このフラグはデフォールトの installation prefix を変更する。また、グローバルのデータベースに加えて、ユーザーのパッケージ・データベースを使った依存性の解決を行えるようにする。このことは --user フラグが指定されると、デフォールトでは、その後のインストール・コマンドではグローバル・データベースの依存関係ではなく、ユーザ・データベースの依存関係が使われることを意味している。

--global

(デフォールト) グローバル・インストールを行う。この場合パッケージの依存関係はグローバル・パッケージ・データベースで解決される。ユーザデータベースの全てのパッケージは無視される。典型例では、最終的なインストール・ステップでは管理者権限が必要だ。

--package-db=db

グローバル・パッケージ・データベースに加えて、このオプションで指定する追加のパッケージ・データベースを使って依存関係を解決するようにする。この場合、ユーザ・パッケージ・データベースの情報は無視される。データベースの実装については、Haskell の実装に依存している。典型的にはデータベースはファイルまたはディレクトリだ。全ての Haskell 処理系がパッケージデータベースの自由をサポートしているわけではない。

--enable-optimization[=n] or -O[n]

(デフォールト) 最適化のフラグが使用可能であればそれを true にしてビルドする。最適化をすると実行ファイルの性能は最適化されるが、実行速度の速いライブラリーやプログラムをビルドするためのビルドの時間がかかる。

オプショナルな n という値は最適化のレベルだ。コンパイラの中には複数の最適化レベルを持っている者がある。最適化の範囲は 0 から 2 までである。レベル 0 は --disable-optimization と同じだ。レベル 1 はパラメータの n が設定されていなければデフォールト・レベルである。レベル 2 は、コンパイラがサポートしていれば、より高い最適化である。レベル 2 では、コンパイルの時間は増し、生成されたコードのサイズが大きくなる傾向がある。

--disable-optimization

最適化を行わないでビルドする。開発時にはこのオプションを使うのが便利だ。ビルドの速度が速くなるが、生成されたライブラリやプログラムの速度は遅い。

--enable-library-profiling or -p

プロファイリングの可能な補助的なバージョンのライブラリを使ってビルドする。Haskell の実装がプロファイリングをサポートしている場合のみに有効。

--disable-library-profiling

(デフォールト) プロファイリングの可能な補助的なバージョンのライブラリを生成しない。

--enable-executable-profiling

プロファイリング可能な実行ファイルを生成する (プロファイリングをサポートしている Haskell の実装に限る)。実行ファイルのプロファイリングが可能になるためには、ライブラリもプロファイリング可能になるようにビルドしてある必要がある。

--disable-executable-profiling

(デフォールト) プロファイリングの可能な実行ファイルを生成しない。

--enable-library-vanilla

(デフォールト) 普通の (プロファイリングできない) ライブラリをビルドする。これは、-enable-library-porfiling オプションとは独立である。両方のフラグを有効にすると、両者のライブラリが生成される。

--disable-library-vanilla

普通のライブラリを生成しない。これは --enable-library-profiling と併用してプロファイリング可能なライブラリだけを生成するために有用である。

--enable-library-for-ghci

(デフォールト) GHCi で利用するのに適したライブラリをビルドする。

--disable-library-for-ghci

すべてのプラットフォームが GHCi をサポートしている訳ではないので、GHCi libs を作成するのに失敗することがある。そのような場合にビルド可能なようにこのフラグを有効にする。

--enable-split-objs

ライブラリをビルドする際に GHC の -split-objs の機能を使う。これは、実行ファイルの最終的なサイズを減少させる。それは、全ライブラリではなく実行ファイルから利用される者だけをリンクするからだ。このダウンサイズを行うとライブラリのビルドの時間が延長し、メモリ使用量がかなり増加する。

--disable-split-objs

(デフォールト) GHC の -split-objs 機能を使わない。このフラグが有効であれば、ライブラリのビルドは速くなるが、ライブラリを利用する実行ファイルのサイズは大きくなる。

--enable-executable-stripping

(デフォールト) バイナリの実行ファイルをインストールするとき、strip プログラムをバイナリに適用する。この処理でバイナリの実行ファイルのサイズをかなり減少させる事ができる。stripping プログラムはデバッグ情報やシンボルを取り除いてバイナリ・ファイルのサイズを減少させる。このような付加的な情報は C プログラムを伝統的なデバッガを使ってデバッグするときに有用だが、Haskell コンパイラで生成されたバイナリ・ファイルをデバッグするのには滅多に利用されることがない。

Haskell の実装のすべてがネイティブのバイナリを生成するわけではない。そのような実装では、このオプションは何の効果も発揮しない。

--disable-executable-stripping

インストールの際にバイナリ・実行ファイルの stripping を行わない。このオプションは gdb を使ってプログラムのデバッグを行いたいときに必要だ。たとえば、Haskell のコードと C のコードの両方を使うプログラムで、C プログラムのパーツのデバッグをしたいときなどだ。もうひとつの利用状況としては、システム・プログラムのパッケージで stripping そのものを扱うプログラムをビルドするときだ。このような例は linux のディストリビューションで見られる。

--enable-shared

シェアード・ライブラリをビルドする。これは別々のコンパイラがほとんどのプラットホームで利用可能なリロケータブルなコードを生成するという意味がある。

--disable-shared

(デフォールト) シェアード・ライブラリをビルドしない。

--extra-include-dirs[=dir]

C ヘッダ・ファイルを検索する外部ディレクトリを指定する。このフラグはディレクトリのリストをとるために複数回使用することができる。

標準のヘッダ・ファイルが、.cabal ファイルには記述されていない標準的でないディレクトリに存在する場合に、このフラグを使用する。このオプションを使うことは、.cabal ファイルの include-dirs フィールドにライブラリや実行ファイルのディレクトリ dir の個々の位置を書き込むのとおなじ効果がある。このオプションを利用する利点は、パッケージを編集する必要が全くないということだ。これらの追加のディレクトリはパッケージをビルドするさいに利用される。また、ライブラリにとっては、そのライブラリを利用するモジュールをコンパイルするときに、そのパッケージ特有のライブラリの置き場所になる。

--extra-lib-dirs[=dir]

システム・ライブラリ・ファイルを検索するための外部ディレクトリを指定する。このフラグは複数回使用してディレクトリのリストを得ることができる。

標準のシステム・ライブラリが、.cabal ファイルには記述されていない標準的でないディレクトリに存在する場合に、このフラグを使用する。このオプションを使うことは、.cabal ファイルの extra-lib-dirs フィールドにライブラリや実行ファイルのディレクトリ dir の個々の位置を書き込むのとおなじ効果がある。このオプションを利用する利点は、パッケージを編集する必要が全くないということだ。これらの追加のディレクトリはパッケージをビルドするさいに利用される。また、ライブラリにとっては、そのライブラリを利用するモジュールをコンパイルするときに、そのパッケージ特有のライブラリの置き場所になる。

単純なビルドのインフラストラクチャーでは、つぎの追加のオプションがある。

--scratchdir=dir

Hugs の出力が置かれるディレクトリを指定する。 (デフォールト: dist/scratch).

前へ 目次 次へ
[PR]
by tnomura9 | 2013-11-02 22:49 | Haskell | Comments(0)