Git Product home page Git Product logo

cmake_format's Introduction

cmake lang

https://travis-ci.com/cheshirekow/cmake_format.svg?branch=master https://readthedocs.org/projects/cmake-format/badge/?version=latest

The cmakelang project provides Quality Assurance (QA) tools for cmake:

  • cmake-annotate can generate pretty HTML from your listfiles
  • cmake-format can format your listfiles nicely so that they don't look like crap.
  • cmake-lint can check your listfiles for problems
  • ctest-to can parse a ctest output tree and translate it into a more structured format (either JSON or XML).

Installation

Install from pypi using pip:

pip install cmakelang

Or see the online documentation for additional options.

Integrations

Usage

usage:
cmake-format [-h]
             [--dump-config {yaml,json,python} | -i | -o OUTFILE_PATH]
             [-c CONFIG_FILE]
             infilepath [infilepath ...]

Parse cmake listfiles and format them nicely.

Formatting is configurable by providing a configuration file. The configuration
file can be in json, yaml, or python format. If no configuration file is
specified on the command line, cmake-format will attempt to find a suitable
configuration for each ``inputpath`` by checking recursively checking it's
parent directory up to the root of the filesystem. It will return the first
file it finds with a filename that matches '\.?cmake-format(.yaml|.json|.py)'.

cmake-format can spit out the default configuration for you as starting point
for customization. Run with `--dump-config [yaml|json|python]`.

positional arguments:
  infilepaths

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -l {error,warning,info,debug}, --log-level {error,warning,info,debug}
  --dump-config [{yaml,json,python}]
                        If specified, print the default configuration to
                        stdout and exit
  --dump {lex,parse,parsedb,layout,markup}
  --no-help             When used with --dump-config, will omit helptext
                        comments in the output
  --no-default          When used with --dump-config, will omit any unmodified
                        configuration value.
  -i, --in-place
  --check               Exit with status code 0 if formatting would not change
                        file contents, or status code 1 if it would
  -o OUTFILE_PATH, --outfile-path OUTFILE_PATH
                        Where to write the formatted file. Default is stdout.
  -c CONFIG_FILES [CONFIG_FILES ...], --config-files CONFIG_FILES [CONFIG_FILES ...]
                        path to configuration file(s)
usage:
cmake-lint [-h]
           [--dump-config {yaml,json,python} | -o OUTFILE_PATH]
           [-c CONFIG_FILE]
           infilepath [infilepath ...]

Check cmake listfile for lint

positional arguments:
  infilepaths

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -l {error,warning,info,debug}, --log-level {error,warning,info,debug}
  --dump-config [{yaml,json,python}]
                        If specified, print the default configuration to
                        stdout and exit
  -o OUTFILE_PATH, --outfile-path OUTFILE_PATH
                        Write errors to this file. Default is stdout.
  --no-help             When used with --dump-config, will omit helptext
                        comments in the output
  --no-default          When used with --dump-config, will omit any unmodified
                        configuration value.
  --suppress-decorations
                        Suppress the file title decoration and summary
                        statistics
  -c CONFIG_FILES [CONFIG_FILES ...], --config-files CONFIG_FILES [CONFIG_FILES ...]
                        path to configuration file(s)

Configuration

cmake-format accepts configuration files in yaml, json, or python format. An example configuration file is given in the online documentation. Providing the structure of your custom commands will help cmake-format to break them up in a pleasant way, and will help cmake-lint detect improper usages of them.

An example short configuration file in python format is:

# -----------------------------
# Options effecting formatting.
# -----------------------------
with section("format"):

  # How wide to allow formatted cmake files
  line_width = 80

  # How many spaces to tab for indent
  tab_size = 2

  # If true, separate flow control names from their parentheses with a space
  separate_ctrl_name_with_space = False

  # If true, separate function names from parentheses with a space
  separate_fn_name_with_space = False

  # If a statement is wrapped to more than one line, than dangle the closing
  # parenthesis on its own line.
  dangle_parens = False

You may specify a path to one or more configuration files with the --config-file command line option. Otherwise, cmake-format will search the ancestry of each infilepath looking for a configuration file to use. If no configuration file is found it will use sensible defaults.

A automatically detected configuration files may have any name that matches \.?cmake-format(.yaml|.json|.py).

If you'd like to create a new configuration file, cmake-format can help by dumping out the default configuration in your preferred format. You can run cmake-format --dump-config [yaml|json|python] to print the default configuration stdout and use that as a starting point.

Markup

cmake-format is for the exceptionally lazy. It will even format your comments for you. It will reflow your comment text to within the configured line width. It also understands a very limited markup format for a couple of common bits.

rulers: A ruler is a line which starts with and ends with three or more non-alphanum or space characters:

# ---- This is a Ruler ----
# cmake-format will know to keep the ruler separated from the
# paragraphs around it. So it wont try to reflow this text as
# a single paragraph.
# ---- This is also a Ruler ---

list: A list is started on the first encountered list item, which starts with a bullet character (*) followed by a space followed by some text. Subsequent lines will be included in the list item until the next list item is encountered (the bullet must be at the same indentation level). The list must be surrounded by a pair of empty lines. Nested lists will be formatted in nested text:

# here are some lists:
#
# * item 1
# * item 2
#
#   * subitem 1
#   * subitem 2
#
# * second list item 1
# * second list item 2

enumerations: An enumeration is similar to a list but the bullet character is some integers followed by a period. New enumeration items are detected as long as either the first digit or the punctuation lines up in the same column as the previous item. cmake-format will renumber your items and align their labels for you:

# This is an enumeration
#
#   1. item
#   2. item
#   3. item

fences: If you have any text which you do not want to be formatted you can guard it with a pair of fences. Fences are three or more tilde characters:

# ~~~
# This comment is fenced
#   and will not be formatted
# ~~~

Note that comment fences guard reflow of comment text, and not cmake code. If you wish to prevent formatting of cmake, code, see below. In addition to fenced-literals, there are three other ways to preserve comment text from markup and/or reflow processing:

  • The --first-comment-is-literal configuration option will exactly preserve the first comment in the file. This is intended to preserve copyright or other formatted header comments.
  • The --literal-comment-pattern configuration option allows for a more generic way to identify comments which should be preserved literally. This configuration takes a regular expression pattern.
  • The --enable-markup configuration option globally enables comment markup processing. It defaults to true so set it to false if you wish to globally disable comment markup processing. Note that trailing whitespace is still chomped from comments.

Disable Formatting Locally

You can locally disable and enable code formatting by using the special comments # cmake-format: off and # cmake-format: on.

Sort Argument Lists

Starting with version 0.5.0, cmake-format can sort your argument lists for you. If the configuration includes autosort=True (the default), it will replace:

add_library(foobar STATIC EXCLUDE_FROM_ALL
            sourcefile_06.cc
            sourcefile_03.cc
            sourcefile_02.cc
            sourcefile_04.cc
            sourcefile_07.cc
            sourcefile_01.cc
            sourcefile_05.cc)

with:

add_library(foobar STATIC EXCLUDE_FROM_ALL
            sourcefile_01.cc
            sourcefile_02.cc
            sourcefile_03.cc
            sourcefile_04.cc
            sourcefile_05.cc
            sourcefile_06.cc
            sourcefile_07.cc)

This is implemented for any argument lists which the parser knows are inherently sortable. This includes the following cmake commands:

  • add_library
  • add_executable

For most other cmake commands, you can use an annotation comment to hint to cmake-format that the argument list is sortable. For instance:

set(SOURCES
    # cmake-format: sortable
    bar.cc
    baz.cc
    foo.cc)

Annotations can be given in a line-comment or a bracket comment. There is a long-form and a short-form for each. The acceptable formats are:

Line Comment long # cmake-format: <tag>
Line Comment short # cmf: <tag>
Bracket Comment long #[[cmake-format: <tag>]]
Bracket Comment short #[[cmf: <tag>]]

In order to annotate a positional argument list as sortable, the acceptable tags are: sortable or sort. For the commands listed above where the positinal argument lists are inherently sortable, you can locally disable sorting by annotating them with unsortable or unsort. For example:

add_library(foobar STATIC
            # cmake-format: unsort
            sourcefile_03.cc
            sourcefile_01.cc
            sourcefile_02.cc)

Note that this is only needed if your configuration has enabled autosort, and you can globally disable sorting by making setting this configuration to False.

Custom Commands

Due to the fact that cmake is a macro language, cmake-format is, by necessity, a semantic source code formatter. In general it tries to make smart formatting decisions based on the meaning of arguments in an otherwise unstructured list of arguments in a cmake statement. cmake-format can intelligently format your custom commands, but you will need to tell it how to interpret your arguments.

Currently, you can do this by adding your command specifications to the additional_commands configuration variables, e.g.:

# Additional FLAGS and KWARGS for custom commands
additional_commands = {
  "foo": {
    "pargs": 2,
    "flags": ["BAR", "BAZ"],
    "kwargs": {
      "HEADERS": '*',
      "SOURCES": '*',
      "DEPENDS": '*',
    }
  }
}

The format is a nested dictionary mapping statement names (dictionary keys) to argument specifications. For the example specification above, the custom command would look something like this:

foo(hello world
    HEADERS a.h b.h c.h d.h
    SOURCES a.cc b.cc c.cc d.cc
    DEPENDS flub buzz bizz
    BAR BAZ)

Reporting Issues and Getting Help

If you encounter any bugs or regressions or if cmake-format doesn't behave in the way that you expect, please post an issue on the github issue tracker. It is especially helpful if you can provide cmake listfile snippets that demonstrate any issues you encounter.

You can also join the #cmake-format channel on our discord server.

Developers

If you want to hack on cmake-format, please see the documentation for contribution rules and guidelines.

Example

Will turn this:

# The following multiple newlines should be collapsed into a single newline




cmake_minimum_required(VERSION 2.8.11)
project(cmakelang_test)

# This multiline-comment should be reflowed
# into a single comment
# on one line

# This comment should remain right before the command call.
# Furthermore, the command call should be formatted
# to a single line.
add_subdirectories(foo bar baz
  foo2 bar2 baz2)

# This very long command should be wrapped
set(HEADERS very_long_header_name_a.h very_long_header_name_b.h very_long_header_name_c.h)

# This command should be split into one line per entry because it has a long argument list.
set(SOURCES source_a.cc source_b.cc source_d.cc source_e.cc source_f.cc source_g.cc source_h.cc)

# The string in this command should not be split
set_target_properties(foo bar baz PROPERTIES COMPILE_FLAGS "-std=c++11 -Wall -Wextra")

# This command has a very long argument and can't be aligned with the command
# end, so it should be moved to a new line with block indent + 1.
some_long_command_name("Some very long argument that really needs to be on the next line.")

# This situation is similar but the argument to a KWARG needs to be on a
# newline instead.
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-sign-compare -Wno-unused-parameter -xx")

set(HEADERS header_a.h header_b.h # This comment should
                                  # be preserved, moreover it should be split
                                  # across two lines.
    header_c.h header_d.h)


# This part of the comment should
# be formatted
# but...
# cmake-format: off
# This bunny should remain untouched:
# .   _ ∩
#   レヘヽ| |
#     (・x・)
#    c( uu}
# cmake-format: on
#          while this part should
#          be formatted again

# This is a paragraph
#
# This is a second paragraph
#
# This is a third paragraph

# This is a comment
# that should be joined but
# TODO(josh): This todo should not be joined with the previous line.
# NOTE(josh): Also this should not be joined with the todo.

if(foo)
if(sbar)
# This comment is in-scope.
add_library(foo_bar_baz foo.cc bar.cc # this is a comment for arg2
                                      # this is more comment for arg2, it should be joined with the first.
    baz.cc) # This comment is part of add_library

other_command(some_long_argument some_long_argument) # this comment is very long and gets split across some lines

other_command(some_long_argument some_long_argument some_long_argument) # this comment is even longer and wouldn't make sense to pack at the end of the command so it gets it's own lines
endif()
endif()


# This very long command should be broken up along keyword arguments
foo(nonkwarg_a nonkwarg_b HEADERS a.h b.h c.h d.h e.h f.h SOURCES a.cc b.cc d.cc DEPENDS foo bar baz)

# This command uses a string with escaped quote chars
foo(some_arg some_arg "This is a \"string\" within a string")

# This command uses an empty string
foo(some_arg some_arg "")

# This command uses a multiline string
foo(some_arg some_arg "
    This string is on multiple lines
")

# No, I really want this to look ugly
# cmake-format: off
add_library(a b.cc
  c.cc         d.cc
           e.cc)
# cmake-format: on

into this:

# The following multiple newlines should be collapsed into a single newline

cmake_minimum_required(VERSION 2.8.11)
project(cmakelang_test)

# This multiline-comment should be reflowed into a single comment on one line

# This comment should remain right before the command call. Furthermore, the
# command call should be formatted to a single line.
add_subdirectories(foo bar baz foo2 bar2 baz2)

# This very long command should be wrapped
set(HEADERS very_long_header_name_a.h very_long_header_name_b.h
            very_long_header_name_c.h)

# This command should be split into one line per entry because it has a long
# argument list.
set(SOURCES
    source_a.cc
    source_b.cc
    source_d.cc
    source_e.cc
    source_f.cc
    source_g.cc
    source_h.cc)

# The string in this command should not be split
set_target_properties(foo bar baz PROPERTIES COMPILE_FLAGS
                                             "-std=c++11 -Wall -Wextra")

# This command has a very long argument and can't be aligned with the command
# end, so it should be moved to a new line with block indent + 1.
some_long_command_name(
  "Some very long argument that really needs to be on the next line.")

# This situation is similar but the argument to a KWARG needs to be on a newline
# instead.
set(CMAKE_CXX_FLAGS
    "-std=c++11 -Wall -Wno-sign-compare -Wno-unused-parameter -xx")

set(HEADERS
    header_a.h header_b.h # This comment should be preserved, moreover it should
                          # be split across two lines.
    header_c.h header_d.h)

# This part of the comment should be formatted but...
# cmake-format: off
# This bunny should remain untouched:
# .   _ ∩
#   レヘヽ| |
#     (・x・)
#    c( uu}
# cmake-format: on
# while this part should be formatted again

# This is a paragraph
#
# This is a second paragraph
#
# This is a third paragraph

# This is a comment that should be joined but
# TODO(josh): This todo should not be joined with the previous line.
# NOTE(josh): Also this should not be joined with the todo.

if(foo)
  if(sbar)
    # This comment is in-scope.
    add_library(
      foo_bar_baz
      foo.cc bar.cc # this is a comment for arg2 this is more comment for arg2,
                    # it should be joined with the first.
      baz.cc) # This comment is part of add_library

    other_command(
      some_long_argument some_long_argument) # this comment is very long and
                                             # gets split across some lines

    other_command(
      some_long_argument some_long_argument some_long_argument) # this comment
                                                                # is even longer
                                                                # and wouldn't
                                                                # make sense to
                                                                # pack at the
                                                                # end of the
                                                                # command so it
                                                                # gets it's own
                                                                # lines
  endif()
endif()

# This very long command should be broken up along keyword arguments
foo(nonkwarg_a nonkwarg_b
    HEADERS a.h b.h c.h d.h e.h f.h
    SOURCES a.cc b.cc d.cc
    DEPENDS foo
    bar baz)

# This command uses a string with escaped quote chars
foo(some_arg some_arg "This is a \"string\" within a string")

# This command uses an empty string
foo(some_arg some_arg "")

# This command uses a multiline string
foo(some_arg some_arg "
    This string is on multiple lines
")

# No, I really want this to look ugly
# cmake-format: off
add_library(a b.cc
  c.cc         d.cc
           e.cc)
# cmake-format: on

cmake_format's People

Contributors

cheshirekow avatar uebelandre avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cmake_format's Issues

User to specify string for fencing

As far as I can tell from the documentation there is no way for the user to specify a custom string (e.g., "#####" as a fence string that wont be formatted.

Can we add this sort of feature. Also it would make sense to make this a list of strings e.g.,

fence_string_specifiers = ["~~~", "#####"]

# first fenced  block

# ~~~
...
...
# ~~~

# second fenced  block

# #####
...
...
# #####

This can be handy in cases where the users don't want to polute their CMakeLists.txt filese with cmake-format: off specifiers

support stdin as input file

I'm trying to use the formatter with vim-autoformat and I'm not seeing what I'm doing wrong.

Error

Formatter cmake_format has errors: b'Traceback (most recent call last):\n  File "/usr/bin/cmake-format", line 11, in <module>\n    load_entry_point(\'cmake-format==0.3.5\', \'console_scripts\', \'cmake-format\')()\n  File "/usr/li
b/python3.6/site-packages/cmake_format/__main__.py", line 243, in main\n    ("if more than one input file is specified, then formatting must be done"\nAssertionError: if more than one input file is specified, then formatting must
be done in-place or written to stdout\n'

The lines in init.vim

let g:formatdef_cmake_format = '"cmake-format --dangle-parens true --line-ending unix --tab-size 0"'
let g:formatters_cmake = ['cmake_format']

I've tried manually running it from the terminal with the same command and on the same file, and it writes to stdout as expected.


Side-note, is --tab-size 0 correct to use tabs instead of spaces? I didn't see anything mentioning tabs/spaces, only that it controlled the number of spaces used.

Parsing fails in multiline command with (escaped) quotes

I'm really looking forward to integrating your project with our workflow. I've been looking for something clang-format-for-cmake-like for years.

Using cmake_format from pypi on python 3.5 in a virtualenv, I've run into a speedbump processing this file:

Error while processing OTHERPATH/dune-xt-common/cmake/modules/DuneXTInstallPythonPackage.cmake
While processing OTHERPATH/dune-xt-common/cmake/modules/DuneXTInstallPythonPackage.cmake
Traceback (most recent call last):
  File "SOMEPATH/python-env/bin/cmake-format", line 11, in <module>
    sys.exit(main())
  File "SOMEPATH/python-env/lib/python3.5/site-packages/cmake_format/__main__.py", line 279, in main
    process_file(cfg, infile, outfile)
  File "SOMEPATH/python-env/lib/python3.5/site-packages/cmake_format/__main__.py", line 41, in process_file
    tok_seqs = parser.digest_tokens(tokens)
  File "SOMEPATH/python-env/lib/python3.5/site-packages/cmake_format/parser.py", line 148, in digest_tokens
    tokens[0].line, tokens[0].col))
AssertionError: Unexpected token of type UNQUOTED_LITERAL at 160:38

I'm only using defaults for config options atm.

Installed packages

Wrapping long arguments

I have noticed some strange behavior when formatting commands with long arguments. When formatting this example CMakeLists.txt, the output I get is:

# Normal wrapping
message(FATAL_ERROR
          "82 character line -----------------------------------------")
# Abnormal wrapping
message(FATAL_ERROR
                    "81 character line ----------------------------------------"
       )
message(
  FATAL_ERROR

    "100 character line ----------------------------------------------------------"
 ) # Closing parenthesis is indented one space!
message(

  "100 character line ----------------------------------------------------------------------"
 ) # Closing parenthesis is indented one space!

I am using version 0.3.2 with the default formatting settings.

comment on it's own line gets moved to previous line

cmake-format 0.3.6

if(test)
  # comment about test_function
  test_function()
endif()

gets reformatted to:

if(test) # comment about test_function
  test_function()
endif()

Is there any way to keep the comment on it's own line? From the example this seems like it should be possible:

if(foo)
  if(sbar)
    # This comment is in-scope.
    add_library(foo_bar_baz

dangle_parens is not working as intended.

(using 0.3.6 on Ubuntu 14.04)
While using json, python, or yaml config files or command line option the trailing parentheses of a multi-line source list is placed at the end of the last line no matter what the setting of dangle_parens. I see no effect of this setting(perhaps a regression issue?).

Use same LICENSE as CMake?

If it's possible, can you make LICENSE permissive? (MIT/BSD/Apache, etc?)

Use the same LICENSE as CMake? https://cmake.org/licensing/

GPL causes conflicts with formatting plugins (since they are permissively licensed). GPL is only forward compatible with OSI licenses, not backward compatible. There are also tricky clauses in GPL that can become non-issues when a simpler license is used.

Cannot invoke cmake-format with Python 3 on Windows

When I try to invoke cmake-format with Python 3 from a command prompt in Windows, I get the following error.

c:\>cmake-format
Traceback (most recent call last):
  File "C:\Python36\Scripts\cmake-format-script.py", line 11, in <module>
    load_entry_point('cmake-format==0.3.2', 'console_scripts', 'cmake-format')()
  File "c:\python36\lib\site-packages\cmake_format\__main__.py", line 184, in main
    for key, value in configuration.Configuration().as_dict().iteritems():
AttributeError: 'dict' object has no attribute 'iteritems'

In Python 3 the iteritems does not exist for dict. Use items instead.

Indented comments incorrectly appended to preceding line

This may be a different aspect of issues #46 and #47

If a comment is already indented, cmake-format seems to consider it as an end-of-line comment for the previous line and appends it to that previous line.

Given this original input file f0.txt, where the if(A) block is unformatted, and the if(E) block is already correctly formatted:

$ cmake-format --version
0.3.6

$ cat f0.txt 
if(A)
# comment about B
baz(B)
# comment about C
baz(C)
endif()

if(E)
  # comment about F
  baz(F)
  # comment about G
  baz(G)
endif()

Running cmake-format on f0.txt to generate f1.txt, where the if(A) block is correctly formatted, but the if(E) block now has comments incorrectly appended to the previous lines:

$ cmake-format f0.txt | tee f1.txt
if(A)
  # comment about B
  baz(B)
  # comment about C
  baz(C)
endif()

if(E) # comment about F
  baz(F) # comment about G
  baz(G)
endif()

Running cmake-format again with the previous output f1.txt to generate f2.txt, where both if(A) and if(E) blocks have comments incorrectly appended to the previous lines:

$ cmake-format f1.txt | tee f2.txt
if(A) # comment about B
  baz(B) # comment about C
  baz(C)
endif()

if(E) # comment about F
  baz(F) # comment about G
  baz(G)
endif()

$ diff -q f1.txt  f2.txt 
Files f1.txt and f2.txt differ

Global option to not format comments?

Can it be possible to turn off comment formatting globally? I'd rather not wrap license headers and commented-out code with # ~~~ or # cmake-format: on/off. cmake-format is also inferring bulleted lists where we didn't mean them.
(These are things we need to fix, but it makes running cmake-format incrementally a little harder).

...

This:

diff --git a/cmake_format/formatter.py b/cmake_format/formatter.py
index 4a80f17..4de3a96 100644
--- a/cmake_format/formatter.py
+++ b/cmake_format/formatter.py
@@ -72,8 +72,7 @@ def format_comment_lines(node, config, line_width):
       inlines.append(token.spelling.strip().lstrip('#'))

   items = markup.parse(inlines)
-  markup_lines = markup.format_items(config, max(10, line_width - 2), items)
-  return ["#" + (" " * len(line[:1])) + line for line in markup_lines]
+  return ["#" + " " + line for item in items for line in item.lines]


 def normalize_line_endings(instr):

works well enough for now

Spaces after control flow commands

I like to have spaces between the command and parentheses for control flow commands (if, elseif, else, endif, while, endwhile, foreach, endforeach, continue, break, return, function, endfunction, macro, endmacro). Having a toggle to preserve that would be nice to have.

Treat NAMESPACE keyword differently so it doesn't line break

Currently in my CMakeLists.txt there is something like

install(EXPORT ${CMAKE_PROJECT_NAME}Targets 
        NAMESPACE jas::
        DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})

After reformatting by cmake-format it becomes

install(EXPORT ${CMAKE_PROJECT_NAME}Targets
        NAMESPACE
        jas::
        DESTINATION
        lib/cmake/${CMAKE_PROJECT_NAME})

which imo is less readable. Is it possible to treat the NAMESPACE and DESTINATION keyword differently so it doesn't line break ?

Support bracket/block comments

Very cool project you've created!

Many of my CMake scripts begin with a multi-line comment of the form #[[comment]]. I get the following error when attempting to format this example CMakeLists.txt:

Error while processing CMakeLists.txt
While processing CMakeLists.txt
Traceback (most recent call last):
File "C:\Python27\Scripts\cmake-format-script.py", line 9, in
load_entry_point('cmake-format==0.3.0', 'console_scripts', 'cmake-format')()
File "c:\python27\lib\site-packages\cmake_format_main_.py", line 211, in main
process_file(config, infile, outfile)
File "c:\python27\lib\site-packages\cmake_format_main_.py", line 35, in process_file
tok_seqs = parser.digest_tokens(tokens)
File "c:\python27\lib\site-packages\cmake_format\parser.py", line 145, in digest_tokens
tokens[0].line, tokens[0].col))
AssertionError: Unexpected token of type UNQUOTED_LITERAL at 2:0

Would you consider adding support for this style of comment?

Allow individual configurations to be passed from the command line instead of just from a config file

First of all I want to thank you for making this awesome tool. I also made a sublime plugin based on this which can run cmake-format automatically on save and I hope you will also find it useful.

Would it be possible to allow individual configurations to be passed from the command line instead of just from a config file? Kind of like what clang-format is doing. The reason why it's good to have this functionality is because it allows me to support custom configuration in my sublime plugin so no .cmake-format or cmake-format.yaml is needed as long as you are using sublime.

Positional argument of keyword incorrectly matched as keyword of containing command

$ cat CMakeLists.txt
[...]
INSTALL(TARGETS gridDynMain RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime)
[...]

Expected:

[...]
- INSTALL(TARGETS gridDynMain RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime)
+ install(TARGETS gridDynMain
+         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT
+         runtime)
[...]

Got:

[...]
- INSTALL(TARGETS gridDynMain RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime)
+ install(TARGETS gridDynMain
+         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT
+         RUNTIME)
[...]

runtime is not a keyword if it immediately follows COMPONENT (or EXPORT/DESTINATION, but I didn't check to see if it was capitalized in either of those cases)

Config uses only default values

Hey. I noticed that updated config has only default values.

get_config returns a dict with tab_size = 10
after config_dict.update(vars(args)) it's 2 (default value)

Therefore it's only using default values, no matter what I put in the config file. Same goes for other parameters.

Python 2.7.14

Add NumPy as Required Package

👋 Hi,

thank you for providing this very useful utility.

The last version of cmake-format (0.4.0) requires the package NumPy. However, setup.py does not list numpy as dependency, as far as I can tell. This causes cmake-format to fail, if you do not install numpy too. For example, after I upgraded to the latest version of cmake-format, the command

cmake-format --version

failed printing the following error message:

Traceback (most recent call last):
  File "/Users/rene/.pyenv/versions/3.7.0/bin/cmake-format", line 11, in <module>
    load_entry_point('cmake-format==0.4.0', 'console_scripts', 'cmake-format')()
  File "/Users/rene/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pkg_resources/__init__.py", line 476, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/Users/rene/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pkg_resources/__init__.py", line 2700, in load_entry_point
    return ep.load()
  File "/Users/rene/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pkg_resources/__init__.py", line 2318, in load
    return self.resolve()
  File "/Users/rene/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pkg_resources/__init__.py", line 2324, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/Users/rene/.pyenv/versions/3.7.0/lib/python3.7/site-packages/cmake_format/__main__.py", line 29, in <module>
    from cmake_format import formatter
  File "/Users/rene/.pyenv/versions/3.7.0/lib/python3.7/site-packages/cmake_format/formatter.py", line 10, in <module>
    import numpy as np
ModuleNotFoundError: No module named 'numpy'

.

Treat COMPONENT keyword differently so it doesn't line break

Currently in my CMakeLists.txt there is something like

install(TARGETS ${PROJECT_NAME}
          EXPORT ${CMAKE_PROJECT_NAME}Targets
          ARCHIVE DESTINATION lib COMPONENT install-app
          LIBRARY DESTINATION lib COMPONENT install-app
          RUNTIME DESTINATION bin COMPONENT install-app)

After reformatting by cmake-format it becomes

install(TARGETS ${PROJECT_NAME}
          EXPORT ${CMAKE_PROJECT_NAME}Targets
          ARCHIVE DESTINATION lib
          COMPONENT install-app
          LIBRARY DESTINATION lib
          COMPONENT install-app
          RUNTIME DESTINATION bin
          COMPONENT install-app)

which imo is less readable. Is it possible to treat the COMPONENT keyword differently so it doesn't line break ?

Allow use of tabs instead of spaces

Some ways I've seen it done is..

  1. A --use-tabs option that doesn't take input
  2. A --use-tabs option that takes a true or false
  3. Using tabs when a setting like --tab-size is set to 0

I'd say either 1 or 2 are good choices, because then --tab-size can still be used for indent level, just with tabs instead of spaces.

Ref #30 (comment)

Function arguments can get incorrectly appended to comments

$ clang-format --version
0.3.6

When I run cmake-format on a code block like this:

my_function(
  item1

  # Some comment
  item2
)

cmake-format gives me the following output:

my_function(item1 # Some comment item2)

There should be a line break before item2.

Consider option to not reflow initial comment block

Our CMake list files start with a copyright block. It would be desirable to have an option that prevents reflow of the first comment block on a file. I can use fences (# ~~~) to work around this, but that seems unnecessarily ugly, maybe?

Thanks for the great tool btw.

Consider supporting dangling parenthesis

It would be good to have an option for dangling parenthesis.

  • dangling parenthesis = on
some_long_command_name(arg arg arg
  arg
)
  • dangling parenthesis = off
some_long_command_name(arg arg arg
  arg)

This idea comes from this comment in #5.

format elseif like if

Currently in my CMakeLists.txt there is something like

if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
   OR CMAKE_COMPILER_IS_GNUCC
   OR CMAKE_COMPILER_IS_GNUCXX)

endif()

After reformatting by cmake-format it keeps it the same, which is great. But for the below

if(MSVC)

elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
       OR CMAKE_COMPILER_IS_GNUCC
       OR CMAKE_COMPILER_IS_GNUCXX)

endif()

it got reformats to

if(MSVC)

elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
       OR
       CMAKE_COMPILER_IS_GNUCC
       OR
       CMAKE_COMPILER_IS_GNUCXX)

endif()

which imo is less readable. Is it possible to change it so elseif gets treated similarly like if?

Incorrect Formatting of Function Call With Interspersed Comments

Steps to Reproduce

  1. Create a file test.cmake with the following content

    cmake_parse_arguments(ARG
                          "SILENT" # optional keywords
                          "" # one value keywords
                          "" # multi value keywords
                          ${ARGN})
  2. Create a configuration file .cmake-format.yaml with the following content

    line_width: 140
  3. Run cmake-format

    cmake-format test.cmake

Expected Result

The command cmake-format prints a nicely formatted version of the given CMake code.

Actual Result

The command produces the following syntactically incorrect code:

cmake_parse_arguments(ARG "SILENT" # optional keywords "" # one value keywords "" # multi value keywords ${ARGN})

.

Possible improvement on formatting "file"

Currently in my CMakeLists.txt there is something like

file(WRITE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
    "include(CMakeFindDependencyMacro)\n"
    "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")

After reformatting by cmake-format it becomes

file(
  WRITE
    ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
    "include(CMakeFindDependencyMacro)\n"
    "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")

which imo is less readable. Is it possible to change it so it doesn't line break twice on the first ( and WRITE?

config file not properly loaded if no extension

The following set of commands don't respect the tab-size:

if(condition)
                   include_diredctories(...)
...
...
endif()

I expect that when I run cmake-format --tab-size 4 that the directives inside the if are going to be indented at 4 spaces as shown below, but instead clang-format overrides it and formats it at 2 spaces anyway.

if(condition)
    include_diredctories(...)
endif()

Any pointers on this?

Invalid CMake syntax crashes cmake format

If I run cmake-format on something like

cmake_minimum_required(VERSION 3.9)

project(test)

sdfsdfsd

There will be error

While processing CMakeLists.txt
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 11, in <module>
    load_entry_point('cmake-format==0.4.0', 'console_scripts', 'cmake-format')()
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/__main__.py", line 336, in main
    process_file(cfg, infile, outfile, args.dump)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/__main__.py", line 58, in process_file
    parse_tree = parser.parse(tokens, config.fn_spec)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 600, in parse
    return consume_body(tokens, cmdspec)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 579, in consume_body
    subtree = consume_statement(tokens, cmdspec)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 451, in consume_statement
    if tokens[0].type != lexer.TokenType.LEFT_PAREN:
IndexError: list index out of range

and here is another example

cmake_minimum_required(VERSION 3.9)

project(test
While processing CMakeLists.txt
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 11, in <module>
    load_entry_point('cmake-format==0.4.0', 'console_scripts', 'cmake-format')()
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/__main__.py", line 336, in main
    process_file(cfg, infile, outfile, args.dump)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/__main__.py", line 58, in process_file
    parse_tree = parser.parse(tokens, config.fn_spec)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 600, in parse
    return consume_body(tokens, cmdspec)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 579, in consume_body
    subtree = consume_statement(tokens, cmdspec)
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 464, in consume_statement
    consume_arguments(subtree, tokens, cmdspec.get(fnname, None), [])
  File "/usr/local/lib/python2.7/dist-packages/cmake_format/parser.py", line 428, in consume_arguments
    .format(node.get_location()))
ValueError: Token stream expired while parsing statement arguments starting at 3:8

It would be nice if cmake-format will just simply do nothing and return if the syntax is invalid. On top of that perhaps show an error message.

The main reason I am asking this is because for the sublime cmake format plugin I am maintaining sublime_cmake_format there is a format on save functionality that is intended for speeding up development, but the problem is if the developer is typing something halfway and habitually click ctrl+s it will crash because the syntax is invalid.

If we reference clang-format, even if we type in some gibberish that can't be compiled clang-format will still attempt to format it into something instead of crashing it, so there's no problem running it with format on save.

Possible improvement on formatting export

Currently in my CMakeLists.txt there is something like

export(TARGETS ${PROJECT_NAME}
       APPEND FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)

After reformatting by cmake-format it becomes

export(TARGETS
       ${PROJECT_NAME}
       APPEND
       FILE
       ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)

which imo is less readable. Is it possible to change it so it doesn't line break on TARGETS and APPEND FILE?

Add non-builtin commands

Add non-builtin commands from standard cmake modules, like write_basic_package_version_file. See #54 for example.

Leading comments inside function bodies cause errors

$ clang-format --version
0.3.6

When I run cmake-format on a code block like this:

my_function(
  # This comment causes a parse error
  stuff
)

cmake-format gives me the following error:

$ cmake-format test.cmake
Error while processing test.cmake
While processing test.cmake
Traceback (most recent call last):
  File "/usr/local/bin/cmake-format", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.6/site-packages/cmake_format/__main__.py", line 312, in main
    process_file(cfg, infile, outfile)
  File "/usr/local/lib/python3.6/site-packages/cmake_format/__main__.py", line 54, in process_file
    fst = parser.construct_fst(tok_seqs)
  File "/usr/local/lib/python3.6/site-packages/cmake_format/parser.py", line 426, in construct_fst
    block_stack[-1].children.append(Statement(tok_seq))
  File "/usr/local/lib/python3.6/site-packages/cmake_format/parser.py", line 315, in __init__
    assert self.body
AssertionError

default codec used to read long_description can't decode utf8 in README.rst

Looks like a very promising project! I tried to install using pip install cmake_format, but got this error message:

(.venv) c:\home\simulator\dchipset>pip install --user cmake_format
Collecting cmake_format
  Downloading <local pypi proxy path>/cmake_format-0.2.0.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "C:\Users\jce\AppData\Local\Temp\pip-build-1yx3c08l\cmake-format\setup.py", line 4, in <module>
        long_description = infile.read()
      File "C:\Python36\lib\encodings\cp1252.py", line 23, in decode
        return codecs.charmap_decode(input,self.errors,decoding_table)[0]
    UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 3710: character maps to <undefined>

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in C:\Users\jce\AppData\Local\Temp\pip-build-1yx3c08l\cmake-format\

Maybe it's because the README.rst file is a symbolic link, which is not really supported on Windows.

Add auto-line ending option

originally requested in the discussion for #26

Add support for line_ending=auto which will detect the current line-ending mode of a file and preserve it on output. Possibly implemented by counting the number of \r\n versus [^\r]\n and picking whichever there are more of.

End of line corruption when writing bracket comment

I am seeing an issue since the last release when formatting files in-place with bracket comments and Windows line endings such as this CMakeLists.txt. When formatted in-place, the lines of the bracket comment pick up an extra carriage return, but the rest of the file is written correctly. The output seems correct when writing to stdout or using Unix line endings.

Possible improvement on formatting "string"

Currently in my CMakeLists.txt there is something like

string(REPLACE "/w44668" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")

After reformatting by cmake-format it becomes

  string(REPLACE "/w44668"
                 ""
                 CMAKE_CXX_FLAGS
                 "${CMAKE_CXX_FLAGS}")

which imo is less readable. Is it possible to change it so it doesn't line break if everything can be fitted to one single line?

allow indent earlier

Currently cmake_format reports it as an error if you indent a line earlier than when it is needed.

For me personally I like to 'overintend' especially with functions and the like that get messy to read otherwise.

It would be great to add an option that would allow this kind of behaviour.

No comment after ending ctrl statement

Hello. Found another bug related to comments. Pretty self-explanatory from the lines below.

Input:

if(True) #Comment
  message(STATUS "nanana")
endif() #ending comment

Output:

if(True) # Comment
  message(STATUS "nanana")
endif()

Expected:

if(True) # Comment
  message(STATUS "nanana")
endif() # ending comment

The funny thing is that this works:

self.do_format_test("""\
      if(True) #Comment
        message(STATUS "nanana")
      endif(True) #ending comment
      """, """\
      if(True) # Comment
        message(STATUS "nanana")
      endif(True) # ending comment
      """)

if conditions with many elements can get pretty messy

Combining conditions with the variable (NOT X) and Breaking on () would help a lot

https://aomedia-review.googlesource.com/c/aom/+/57102/3/test/test.cmake

    if (("${var}" MATCHES "_TEST_" AND NOT
         "${var}" MATCHES
         "_DATA_\|_CMAKE_\|INTRA_PRED\|_COMPILED\|_HOSTING\|_PERF_\|CODER_")
        OR (CONFIG_AV1_ENCODER AND CONFIG_ENCODE_PERF_TESTS AND
            "${var}" MATCHES "_ENCODE_PERF_TEST_")
        OR (CONFIG_AV1_DECODER AND CONFIG_DECODE_PERF_TESTS AND
            "${var}" MATCHES "_DECODE_PERF_TEST_")
        OR (CONFIG_AV1_ENCODER AND "${var}" MATCHES "_TEST_ENCODER_")
        OR (CONFIG_AV1_DECODER AND  "${var}" MATCHES "_TEST_DECODER_"))
      list(APPEND aom_test_source_vars ${var})
    endif ()

converted

    if((
       "${var}"
       MATCHES
       "_TEST_"
       AND
       NOT
       "${var}"
       MATCHES
       "_DATA_\|_CMAKE_\|INTRA_PRED\|_COMPILED\|_HOSTING\|_PERF_\|CODER_"
       )
       OR
       (
       CONFIG_AV1_ENCODER
       AND
       CONFIG_ENCODE_PERF_TESTS
       AND
       "${var}"
       MATCHES
       "_ENCODE_PERF_TEST_"
       )
       OR
       (
       CONFIG_AV1_DECODER
       AND
       CONFIG_DECODE_PERF_TESTS
       AND
       "${var}"
       MATCHES
       "_DECODE_PERF_TEST_"
       )
       OR
       (
       CONFIG_AV1_ENCODER
       AND
       "${var}"
       MATCHES
       "_TEST_ENCODER_"
       )
       OR
       (
       CONFIG_AV1_DECODER
       AND
       "${var}"
       MATCHES
       "_TEST_DECODER_"
       ))

https://aomedia-review.googlesource.com/c/aom/+/57102/3/test/test_data_download_worker.cmake
if (NOT AOM_ROOT OR NOT AOM_CONFIG_DIR OR NOT AOM_TEST_FILE OR NOT AOM_TEST_CHECKSUM)

converted to

if(NOT
   AOM_ROOT
   OR
   NOT
   AOM_CONFIG_DIR
   OR
   NOT
   AOM_TEST_FILE
   OR
   NOT
   AOM_TEST_CHECKSUM)

cmake-format removes entire while()... endwhile() sections

There seems to be a scary bug when running cmake-format in scripts that use while(...) loops! cmake-format just removes them!

Sample file:

set(A "a")


while(condition)
    fun1()
    fun2()
endwhile()

set(B "b")

If you run cmake-format on the latter we end up with this:

set(A "a")



set(B "b")

Any pointers?

Corruption upon trailing whitespace

Thanks for this cool program! I've been looking for something like this for CMake for a while.

I noticed that trailing whitespace seems to confuse the program.

Input CMakeLists.txt:

set(FOO "f") 
set(BAR "b")

Note the trailing whitespace on the first line:
screen shot 2018-02-18 at 09 14 40

Test:

$ python2.7 -m cmake_format CMakeLists.txt

Expected:

set(FOO "f")
set(BAR "b")

Got:

set(FOO "f")set(BAR "b")

separate-ctrl-name-with-space not producing consistent results

Formatting:

project(sxx)
cmake_minimum_required(VERSION 2.8)

include_directories(include)

set(CMAKE_CXX_FLAGS "-std=c++11 -Werror -Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic -Wold-style-cast -Wcast-align -Wunused -Wcast-qual -Woverloaded-virtual -Wconversion -Wformat-security -Wwrite-strings -fdiagnostics-show-option")

if (COVERAGE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
elseif (ASAN)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O1 -fno-omit-frame-pointer -fsanitize=address -fsanitize=leak")
elseif (UBSAN)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fsanitize=undefined")
elseif (TSAN)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O1 -fsanitize=thread")
else ()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif ()

add_executable(${PROJECT_NAME} src/sxx.cpp)

target_link_libraries(${PROJECT_NAME} PocoFoundation)

# packaging

install(TARGETS ${PROJECT_NAME} DESTINATION bin)

find_program(rpmbuild_path "rpmbuild" FALSE)
if (rpmbuild_path) # is rpm based
  message(STATUS "rpmbuild found, enabling RPM for the 'package' target")
  list(APPEND CPACK_GENERATOR RPM)
  if (EXISTS "/etc/redhat-release") # is rhel or centos
    execute_process(COMMAND /bin/bash -c "rpm -E %{?dist} | sed -e 's/\\.//g' | sed 's/centos//g'"
      OUTPUT_VARIABLE DISTRO_AND_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
    set(CPACK_RPM_PACKAGE_REQUIRES "poco-foundation")
  else () # is opensuse
    execute_process(COMMAND /bin/bash -c ". /etc/os-release; printf \"%s%.0f\" \"$ID\" \"$VERSION_ID\""
      OUTPUT_VARIABLE DISTRO_AND_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
    set(CPACK_RPM_PACKAGE_REQUIRES "libPocoFoundation60")
  endif ()
endif ()

find_program(dpkg_path "dpkg" FALSE)
if (dpkg_path) # is dpkg based
  message(STATUS "dpkg found, enabling DEB for the 'package' target")
  list(APPEND CPACK_GENERATOR DEB)
  execute_process(COMMAND /bin/bash -c "printf \"$(lsb_release -i | awk '{printf tolower($NF)}')\""
    OUTPUT_VARIABLE DISTRO)

  if (${DISTRO} STREQUAL "debian") # is debian
    execute_process(COMMAND /bin/bash -c "printf \"%.f\" \"$(lsb_release -r | awk '{printf int($NF)}')\""
      OUTPUT_VARIABLE DISTRO_VERSION)
    if (${DISTRO_VERSION} EQUAL 8)
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation9")
    else ()
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation46")
    endif ()
  else () # is ubuntu
    execute_process(COMMAND /bin/bash -c "printf \"$(lsb_release -r | awk '{printf $NF}')\""
      OUTPUT_VARIABLE DISTRO_VERSION)
    if (${DISTRO_VERSION} EQUAL 14.04) 
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation9")
    elseif (${DISTRO_VERSION} EQUAL 16.04)
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation9v5")
    else ()
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation50")
    endif ()
  endif ()

  set(DISTRO_AND_VERSION "${DISTRO}${DISTRO_VERSION}")
endif ()

execute_process(COMMAND /bin/bash -c "uname -m" OUTPUT_VARIABLE CPU_ARCH
  OUTPUT_STRIP_TRAILING_WHITESPACE)

set(CPACK_PACKAGE_CONTACT "[email protected]")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "sxx is a tool that allows you to easily run shell commands on multiple hosts or transfer files to multiple hosts")
set(CPACK_PACKAGE_URL "https://github.com/ericcurtin/sxx")
set(CPACK_PACKAGE_VERSION_MAJOR 1)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 1)
set(CPACK_PACKAGE_VERSION
    "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${DISTRO_AND_VERSION}-${CPU_ARCH}")

include(CPack)

# man pages

add_custom_target(doc)

add_custom_command(TARGET doc SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/doc/sxx.pod
  COMMAND podchecker --nowarnings ${CMAKE_CURRENT_SOURCE_DIR}/doc/sxx.pod
  COMMAND pod2man -c 'sxx manual' -q none -r 'sxx ${CPACK_PACKAGE_VERSION}' ${CMAKE_CURRENT_SOURCE_DIR}/doc/sxx.pod ${CMAKE_CURRENT_BINARY_DIR}/sxx.1
  COMMAND gzip -f ${CMAKE_CURRENT_BINARY_DIR}/sxx.1
  OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/sxx.1.gz)

add_custom_command(TARGET doc SOURCE doc
  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/sxx.1.gz)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sxx.1.gz
  DESTINATION ${CMAKE_install_PREFIX}/man/man1)

# ctest

enable_testing()
add_subdirectory(test)

# make format - clang-format

add_custom_target(format COMMAND clang-format -i -style=file ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp)

with:

cmake-format CMakeLists.txt --separate-ctrl-name-with-space True --line-ending unix --keyword-case upper --command-case lower

produces:

project(sxx)
cmake_minimum_required(VERSION 2.8)

include_directories(include)

set(
  CMAKE_CXX_FLAGS
  "-std=c++11 -Werror -Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic -Wold-style-cast -Wcast-align -Wunused -Wcast-qual -Woverloaded-virtual -Wconversion -Wformat-security -Wwrite-strings -fdiagnostics-show-option"
  )

if (COVERAGE)
  set(
    CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
elseif(ASAN)
  set(
    CMAKE_CXX_FLAGS
    "${CMAKE_CXX_FLAGS} -g -O1 -fno-omit-frame-pointer -fsanitize=address -fsanitize=leak"
    )
elseif(UBSAN)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fsanitize=undefined")
elseif(TSAN)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O1 -fsanitize=thread")
else()
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif ()

add_executable(${PROJECT_NAME} src/sxx.cpp)

target_link_libraries(${PROJECT_NAME} PocoFoundation)

# packaging

install(TARGETS ${PROJECT_NAME} DESTINATION bin)

find_program(rpmbuild_path "rpmbuild" FALSE)
if (rpmbuild_path) # is rpm based
  message(STATUS "rpmbuild found, enabling RPM for the 'package' target")
  list(APPEND CPACK_GENERATOR RPM)
  if (EXISTS "/etc/redhat-release") # is rhel or centos
    execute_process(
      COMMAND /bin/bash -c
              "rpm -E %{?dist} | sed -e 's/\\.//g' | sed 's/centos//g'"
      OUTPUT_VARIABLE DISTRO_AND_VERSION
      OUTPUT_STRIP_TRAILING_WHITESPACE)
    set(CPACK_RPM_PACKAGE_REQUIRES "poco-foundation")
  else() # is opensuse
    execute_process(
      COMMAND /bin/bash -c
              ". /etc/os-release; printf \"%s%.0f\" \"$ID\" \"$VERSION_ID\""
      OUTPUT_VARIABLE DISTRO_AND_VERSION
      OUTPUT_STRIP_TRAILING_WHITESPACE)
    set(CPACK_RPM_PACKAGE_REQUIRES "libPocoFoundation60")
  endif ()
endif ()

find_program(dpkg_path "dpkg" FALSE)
if (dpkg_path) # is dpkg based
  message(STATUS "dpkg found, enabling DEB for the 'package' target")
  list(APPEND CPACK_GENERATOR DEB)
  execute_process(
    COMMAND /bin/bash -c
            "printf \"$(lsb_release -i | awk '{printf tolower($NF)}')\""
    OUTPUT_VARIABLE DISTRO)

  if (${DISTRO} STREQUAL "debian") # is debian
    execute_process(
      COMMAND /bin/bash -c
              "printf \"%.f\" \"$(lsb_release -r | awk '{printf int($NF)}')\""
      OUTPUT_VARIABLE DISTRO_VERSION)
    if (${DISTRO_VERSION} EQUAL 8)
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation9")
    else()
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation46")
    endif ()
  else() # is ubuntu
    execute_process(COMMAND /bin/bash -c
                            "printf \"$(lsb_release -r | awk '{printf $NF}')\""
                    OUTPUT_VARIABLE DISTRO_VERSION)
    if (${DISTRO_VERSION} EQUAL 14.04)
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation9")
    elseif(${DISTRO_VERSION} EQUAL 16.04)
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation9v5")
    else()
      set(CPACK_DEBIAN_PACKAGE_DEPENDS "libpocofoundation50")
    endif ()
  endif ()

  set(DISTRO_AND_VERSION "${DISTRO}${DISTRO_VERSION}")
endif ()

execute_process(COMMAND /bin/bash -c "uname -m"
                OUTPUT_VARIABLE CPU_ARCH
                OUTPUT_STRIP_TRAILING_WHITESPACE)

set(CPACK_PACKAGE_CONTACT "[email protected]")
set(
  CPACK_PACKAGE_DESCRIPTION_SUMMARY
  "sxx is a tool that allows you to easily run shell commands on multiple hosts or transfer files to multiple hosts"
  )
set(CPACK_PACKAGE_URL "https://github.com/ericcurtin/sxx")
set(CPACK_PACKAGE_VERSION_MAJOR 1)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 1)
set(
  CPACK_PACKAGE_VERSION
  "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}"
  )
set(
  CPACK_PACKAGE_FILE_NAME
  "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${DISTRO_AND_VERSION}-${CPU_ARCH}")

include(CPack)

# man pages

add_custom_target(doc)

add_custom_command(TARGET
                   doc
                   SOURCE
                   ${CMAKE_CURRENT_SOURCE_DIR}/doc/sxx.pod
                   COMMAND podchecker
                           --NOWARNINGS ${CMAKE_CURRENT_SOURCE_DIR}/doc/sxx.pod
                   COMMAND pod2man -C 'sxx manual' -Q none -R
                           'sxx ${CPACK_PACKAGE_VERSION}'
                           ${CMAKE_CURRENT_SOURCE_DIR}/doc/sxx.pod
                           ${CMAKE_CURRENT_BINARY_DIR}/sxx.1
                   COMMAND gzip -F ${CMAKE_CURRENT_BINARY_DIR}/sxx.1 OUTPUTS
                           ${CMAKE_CURRENT_BINARY_DIR}/sxx.1.gz)

add_custom_command(TARGET
                   doc
                   SOURCE
                   doc
                   DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/sxx.1.gz)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sxx.1.gz
        DESTINATION ${CMAKE_install_PREFIX}/man/man1)

# ctest

enable_testing()
add_subdirectory(test)

# make format - clang-format

add_custom_target(format
                  COMMAND clang-format -I -STYLE=FILE
                          ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
                          ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp
                          ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp)

I would expect "if (", "elseif (", "else (" and "endif (" consistently.

AssertionError when using on CMakeLists.txt

$ cmake-format CMakeLists.txt
Error while processing CMakeLists.txt
While processing CMakeLists.txt
Traceback (most recent call last):
  File "/Users/$USER/miniconda3/envs/python27/bin/cmake-format", line 11, in <module>
    load_entry_point('cmake-format', 'console_scripts', 'cmake-format')()
  File "/Users/$USER/GitRepos/cmake_format/cmake_format/__main__.py", line 111, in main
    process_file(config, infile, outfile)
  File "/Users/$USER/GitRepos/cmake_format/cmake_format/__main__.py", line 26, in process_file
    fst = parser.construct_fst(tok_seqs)
  File "/Users/$USER/GitRepos/cmake_format/cmake_format/parser.py", line 365, in construct_fst
    assert block_stack and block_stack[-1].block_type == IF_BLOCK
AssertionError

Support keyword/value alignment

For commands with many keyword arguments, it can be nice to align the values to the keywords like this:

some_command(
  KEYWORD       arg
  MULTI_KEYWORD arg
                arg)

Where values are aligned to indentation levels. Combined with #5, it could look like this:

some_command(
  KEYWORD
    arg
  MULTI_KEYWORD
    arg
    arg)

The MULTI_KEYWORD arguments could also be collapsed to a single line following line length limits.

override config file option not up to date in readme

There are some new configs to set in the Configuration section,

dangle_parens = False
bullet_char = u'*'
enum_char = u'.'
line_ending = u'unix'
command_case = u'lower'

but they are not mentioned in the Usage --> Override configfile options section. It should be updated as well. I guess some of them myself like cmake-format --command-case upper CMakeLists.txt and it actually works.

Normally I will do a PR for this but I know PR is generally not accepted in this repo.

Incorrect Formatting of Function Call With Trailing Comment

Steps to Reproduce

  1. Create a file test.cmake with the following content

    set (answer 
         42 # comment  
        )
  2. Run cmake-format

    cmake-format test.cmake

Expected Result

The command cmake-format prints a nicely formatted version of the given CMake code.

Actual Result

The command produces the following syntactically incorrect code:

set(answer 42 # comment)

.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.