Cờ GCC hữu ích cho C


157

Ngoài cài đặt -Wall và cài đặt -std=XXX, còn có các cờ trình biên dịch nào thực sự hữu ích nhưng ít được biết đến để sử dụng trong C không?

Tôi đặc biệt quan tâm đến bất kỳ cảnh báo bổ sung nào, và / hoặc biến cảnh báo thành lỗi trong một số trường hợp để giảm thiểu tuyệt đối mọi trường hợp không phù hợp.


9
Chà -save-temps, -Wshadow-fmudflaplà những phát hiện vĩ đại nhất mà tôi không biết, cảm ơn tất cả.
Matt tham gia

Bối cảnh, theo như tôi có thể nói: chạy gcc -c [flags-go-here] -o myprog.o myprog.cđể biên dịch (không liên kết) một chương trình C.
Rory O'Kane

Câu trả lời:


64

Một số -ftùy chọn tạo mã rất thú vị:

  • Các -ftrapvchức năng sẽ làm cho chương trình để hủy bỏ vào ký số nguyên tràn (chính thức "hành vi không xác định" trong C).

  • -fverbose-asmlà hữu ích nếu bạn đang biên dịch -Sđể kiểm tra đầu ra lắp ráp - nó thêm một số ý kiến ​​thông tin.

  • -finstrument-functions thêm mã để gọi các hàm lược tả do người dùng cung cấp tại mỗi điểm nhập và thoát của hàm.


Đối với -ftrapv, hãy xem tại đây stackoverflow.com/questions/20851061/ cấp .. có vẻ như có một lỗi đang chờ đợi để được sửa chữa.
Arjun Sreedharan 3/2/2015

Bạn có thể kiểm tra các bình luận trên?
Suraj Jain

-ftrapv về cơ bản được thay thế bởi -fsanitize = Sign-integ-overflow.
Marc Glisse

139

Đây là của tôi:

  • -Wextra, -Wall: thiết yếu.
  • -Wfloat-equal: hữu ích vì thường kiểm tra các số dấu phẩy động cho đẳng thức là xấu.
  • -Wundef: cảnh báo nếu một định danh chưa được khởi tạo được đánh giá trong một lệnh #if.
  • -Wshadow: cảnh báo bất cứ khi nào một biến cục bộ làm mờ một biến cục bộ, tham số hoặc biến toàn cục hoặc bất cứ khi nào một hàm tích hợp bị che khuất.
  • -Wpointer-arith: cảnh báo nếu có bất cứ điều gì phụ thuộc vào kích thước của hàm hoặc của void.
  • -Wcast-align: cảnh báo bất cứ khi nào một con trỏ được đúc sao cho sự liên kết cần thiết của mục tiêu được tăng lên. Ví dụ: cảnh báo nếu a char *được truyền tới một int *máy trên đó số nguyên chỉ có thể được truy cập ở ranh giới hai hoặc bốn byte.
  • -Wstrict-prototypes: cảnh báo nếu một hàm được khai báo hoặc định nghĩa mà không chỉ định các loại đối số.
  • -Wstrict-overflow=5: cảnh báo về các trường hợp trình biên dịch tối ưu hóa dựa trên giả định rằng tràn tràn đã ký không xảy ra. (Giá trị 5 có thể quá nghiêm ngặt, xem trang hướng dẫn.)
  • -Wwrite-strings: cung cấp cho hằng chuỗi const char[độ dài loại ]sao cho việc sao chép địa chỉ của một const char *con trỏ vào một con trỏ không sẽ nhận được cảnh báo.
  • -Waggregate-return: cảnh báo nếu bất kỳ chức năng nào trả về cấu trúc hoặc công đoàn được xác định hoặc gọi.
  • -Wcast-qual: cảnh báo bất cứ khi nào một con trỏ được chọn để loại bỏ vòng loại loại khỏi loại mục tiêu * .
  • -Wswitch-default: cảnh báo bất cứ khi nào một switchtuyên bố không có defaulttrường hợp * .
  • -Wswitch-enum: cảnh báo bất cứ khi nào một switchcâu lệnh có một chỉ mục thuộc loại liệt kê và thiếu một casecho một hoặc nhiều mã được đặt tên của bảng liệt kê đó * .
  • -Wconversion: cảnh báo cho các chuyển đổi ngầm có thể thay đổi giá trị * .
  • -Wunreachable-code: cảnh báo nếu trình biên dịch phát hiện mã đó sẽ không bao giờ được thực thi * .

Những người được đánh dấu * đôi khi đưa ra quá nhiều cảnh báo giả, vì vậy tôi sử dụng chúng khi cần thiết.


11
Danh sách khá đầy đủ, chỉ muốn thêm một; -Wformat=2: Kiểm tra định dạng bổ sung trên các chức năng printf / scanf.
schot

1
arent tất cả những điều này ngụ ý bởi -Wall?
chacham15

2
@ chacham15, không, tôi không nghĩ vậy. gcc.gnu.org/onlinesocs/gcc/Warning-Options.html
Alok Singhal

1
@Alok hmm, có lẽ nó không chuẩn trong số các bản phân phối? Tôi biết rằng trên mbp của tôi, tôi phải tắt một cách rõ ràng -Wwrite-stringsbởi vì tôi ghét nó rất nhiều.
chacham15

@ chacham15, có thể. Nhưng mô tả -Wwrite-stringscụ thể nói rằng nó không phải là một phần của -Wall: gcc.gnu.org/onlinesocs/gcc/ mẹo . Có lẽ một cái gì đó khác trong thiết lập của bạn là thiết lập cờ đó? Hoặc có thể bạn đang biên dịch C ++?
Alok Singhal

52

Luôn luôn sử dụng -Ohoặc cao hơn ( -O1, -O2,-Os , vv). Ở mức tối ưu hóa mặc định, gcc dành cho tốc độ biên dịch và không thực hiện đủ phân tích để cảnh báo về những thứ như các biến đơn vị.

Xem xét việc đưa ra -Werrorchính sách, vì các cảnh báo không dừng việc biên dịch có xu hướng bị bỏ qua.

-Wall khá nhiều bật các cảnh báo rất có thể là lỗi.

Cảnh báo bao gồm trong -Wextraxu hướng gắn cờ mã phổ biến, hợp pháp. Chúng có thể hữu ích cho việc đánh giá mã (mặc dù các chương trình kiểu lint tìm thấy nhiều cạm bẫy linh hoạt hơn), nhưng tôi sẽ không bật chúng để phát triển bình thường.

-Wfloat-equal là một ý tưởng tốt nếu các nhà phát triển trong dự án không quen thuộc với dấu phẩy động và là một ý tưởng tồi nếu có.

-Winit-selflà hữu ích; Tôi tự hỏi tại sao nó không được bao gồm trong -Wuninitialized.

-Wpointer-arithlà hữu ích nếu bạn có mã di động chủ yếu không hoạt động -pedantic.


9
+1 cho "-Wfloat-bằng là một ý tưởng tốt nếu các nhà phát triển trong dự án không quen với điểm nổi và ý tưởng tồi nếu có." đặc biệt là nửa sau của nó. :-)
R .. GitHub DỪNG GIÚP ICE

39
-save-temps

Điều này để lại kết quả của bộ tiền xử lý và lắp ráp.

Nguồn được xử lý trước là hữu ích để gỡ lỗi macro.

Việc lắp ráp rất hữu ích để xác định những gì tối ưu hóa đã có hiệu lực. Chẳng hạn, bạn có thể muốn xác minh rằng GCC đang thực hiện tối ưu hóa cuộc gọi đuôi trên một số chức năng đệ quy, vì nếu không có nó, bạn có thể có khả năng tràn ngăn xếp.


Tôi đã tự hỏi làm thế nào bạn có nó để làm điều đó ... Tôi luôn luôn yêu cầu gcc bỏ hội đồng nếu tôi cần nó.

35

Tôi ngạc nhiên chưa ai nói điều này - cờ hữu ích nhất theo như tôi quan tâm là -gđưa thông tin gỡ lỗi vào tệp thực thi để bạn có thể gỡ lỗi và bước qua nguồn (trừ khi bạn thành thạo và đọc lắp ráp và như stepilệnh) của một chương trình trong khi nó đang thực thi.


35

-fmudflap - thêm kiểm tra thời gian chạy cho tất cả các hoạt động con trỏ rủi ro để bắt UB. Điều này có hiệu quả miễn dịch chương trình của bạn một lần nữa tràn bộ đệm và giúp bắt tất cả các loại con trỏ lơ lửng.

Đây là bản demo:

$ cat mf.c 
int main()
{
 int a[10];
 a[10]=1; // <-- o noes, line 4
}

$ gcc -fmudflap mf.c -lmudflap
$ ./a.out 
*******
mudflap violation 1 (check/write): time=1280862302.170759 ptr=0x7fff96eb3d00 size=44
pc=0x7f3a575503c1 location=`mf.c:4:2 (main)'
      /usr/lib/libmudflap.so.0(__mf_check+0x41) [0x7f3a575503c1]
      ./a.out(main+0x90) [0x400a54]
      /lib/libc.so.6(__libc_start_main+0xfd) [0x7f3a571e2c4d]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0xf9c560: name=`mf.c:3:6 (main) a'
bounds=[0x7fff96eb3d00,0x7fff96eb3d27] size=40 area=stack check=0r/3w liveness=3
alloc time=1280862302.170749 pc=0x7f3a57550cb1
number of nearby objects: 1

Hmmm, Mudflap có vẻ khá khó chịu: P
Matt Joiner

9
-fmudflapkhông còn được hỗ trợ kể từ GCC 4.9, bạn nhận được warning: switch '-fmudflap' is no longer supported. Nó được thay thế bởi addressSanitizer.
Agostino

21

Không thực sự liên quan đến C / C ++, nhưng dù sao cũng hữu ích:

@file

Đặt tất cả các cờ tốt ở trên (mà tất cả các bạn đã chỉ định) vào một 'tệp' và sử dụng cờ ở trên để sử dụng tất cả các cờ trong tệp đó cùng nhau.

ví dụ:

Tập tin: Trình biên dịchFlags

-Tường

-std = c99

-Wextra

Sau đó biên dịch:

gcc yourSourceFile @compilerFlags

15

-march=native để tạo mã được tối ưu hóa cho nền tảng (= chip) mà bạn đang biên dịch


2
Nếu bạn đang biên dịch cho các máy không phải là nguồn gốc mà bạn không biết mục tiêu, bạn có thể sử dụng mtune = xxx để tối ưu hóa mà không cần sử dụng các bộ hướng dẫn. Ví dụ mtune = generic được cập nhật với các bộ xử lý trường hợp "trung bình".
Turix

15

Nếu bạn cần biết các cờ tiền xử lý được trình biên dịch xác định trước:

echo | gcc -E -dM -

13

Nó không thực sự hữu ích để phát hiện lỗi, nhưng -masm=inteltùy chọn hiếm khi được đề cập giúp sử dụng -Sđể kiểm tra đầu ra lắp ráp đẹp hơn nhiều.

Cú pháp lắp ráp AT & T làm tổn thương đầu tôi quá nhiều.


2
Sự khác biệt giữa AT & T và Intel với tôi là sự khác biệt giữa C # và Java. Chỉ cần cú pháp. Cả hai khủng khiếp. :)
Matt Joiner

2
+1 @michael để tạo gcc sử dụng cú pháp intel thay vì thần khủng khiếp tại & t. Kiểm tra lắp ráp sử dụng đủ chu kỳ não - không cần lãng phí chu kỳ não mà src đi trước định mệnh trong opcodes. Bây giờ nếu chỉ có gcc hỗ trợ nội tuyến __asm ​​{} như các trình biên dịch khác thì chúng ta đã thiết lập xong!
Greatwolf

10

Makefile của tôi thường chứa

  CFLAGS= -Wall -Wextra -Weffc++ -Os -ggdb
  ...
  g++ $(CFLAGS) -o junk $<
  gcc $(CFLAGS) -o $@ $<
  rm -f junk

Điều quan trọng nhất trong số các tùy chọn này đã được thảo luận trước đây, vì vậy tôi sẽ chỉ ra hai tính năng chưa được chỉ ra:

Mặc dù tôi đang làm việc trên một cơ sở mã cần đơn giản C về tính di động đối với một số nền tảng vẫn không có trình biên dịch C ++ đàng hoàng, tôi vẫn biên dịch "thêm" với trình biên dịch C ++ (ngoài trình biên dịch C). Điều đó có 3 lợi ích:

  1. trình biên dịch C ++ thỉnh thoảng cung cấp cho tôi các thông báo cảnh báo tốt hơn trình biên dịch C.
  2. Trình biên dịch C ++ chấp nhận tùy chọn -weffc ++, đôi khi cung cấp cho tôi một số mẹo hữu ích, tôi sẽ bỏ lỡ nếu tôi chỉ biên dịch nó ở dạng C.
  3. Tôi có thể giữ mã tương đối dễ dàng để chuyển sang C ++, tránh một vài điều kiện biên trong đó mã C đơn giản là mã C ++ không hợp lệ (chẳng hạn như xác định một biến có tên là "bool").

Vâng, tôi là một Pollyanna lạc quan vô vọng, luôn nghĩ rằng chắc chắn bất kỳ tháng nào bây giờ một nền tảng sẽ bị tuyên bố là lỗi thời hoặc có được trình biên dịch C ++ đàng hoàng và cuối cùng chúng ta có thể chuyển sang C ++. Trong tâm trí của tôi, đó là điều không thể tránh khỏi - câu hỏi duy nhất là liệu điều đó xảy ra trước hay sau khi quản lý cuối cùng đã đưa ra cho mọi người một con ngựa. :-)


Một điểm tốt với việc viết nó là C ++, tôi xem xét điều này thường xuyên. (tập hợp con một cách tự nhiên)
Matt Joiner

6
Tôi nên chỉ ra rằng C không được ủng hộ C ++ sẽ không bao giờ xảy ra, xin lỗi :)
Matt Joiner

4
xem xét -o / dev / null thay vì rm -f rác
ulidtko

9
-Wstrict-prototypes -Wmissing-prototypes

10
-Wold-style-definitionnếu bạn phải đối phó với những người tái phạm, những người nghĩ rằng các chức năng theo phong cách K & R là một ý tưởng tốt, ngay cả với các tuyên bố nguyên mẫu. (Tôi phải đối phó với những người như vậy. Nó thực sự làm tôi khó chịu khi tôi tìm thấy mã mới được viết bằng K & R. Thật tệ khi có những thứ K & R kế thừa không được sửa, nhưng mã mới! Grump !!!)
Jonathan Leffler

9

Đây là một lá cờ tuyệt vời chưa được đề cập:

-Werror-implicit-function-declaration

Đưa ra lỗi bất cứ khi nào một chức năng được sử dụng trước khi được khai báo.


8
man gcc

Hướng dẫn có đầy đủ các cờ thú vị với mô tả tốt. Tuy nhiên, -Wall có thể sẽ làm cho gcc càng dài càng tốt. Nếu bạn muốn dữ liệu thú vị hơn, bạn nên xem valgrind hoặc một số công cụ khác để kiểm tra lỗi.


1
Đó là loooooooooooooooooooooooooooooooong, mặc dù. man gcc | nlbáo cáo hơn 11000 dòng. Đó là nhiều hơn các bashtrang web khét tiếng !
new123456

12
Cảm ơn chúa, họ đã nhồi nhét nó vào một trang người đàn ông, thay vì một trong những trang "thông tin" đáng tin cậy.
Matt Joiner

6

Vâng, -Wextranên là tiêu chuẩn, quá. -Werrorbiến cảnh báo thành lỗi (có thể rất khó chịu, đặc biệt nếu bạn biên dịch mà không có -Wno-unused-result). -pedantickết hợp với std=c89cung cấp cho bạn các cảnh báo bổ sung nếu bạn sử dụng các tính năng của C99.

Nhưng đó là về nó. Bạn không thể điều chỉnh trình biên dịch C thành một kiểu lưu nhiều hơn bản thân C.


6

-M* gia đình lựa chọn.

Những thứ này cho phép bạn viết các tệp tự động tìm ra các tệp tiêu đề mà các tệp nguồn c hoặc c ++ của bạn nên phụ thuộc vào. GCC sẽ tạo các tệp tạo với thông tin phụ thuộc này và sau đó bạn bao gồm chúng từ tệp tạo chính của bạn.

Dưới đây là ví dụ về tệp tạo tệp cực kỳ chung sử dụng -MD và -MP sẽ biên dịch một thư mục chứa đầy đủ các tệp nguồn và tiêu đề c ++ và tự động tìm ra tất cả các phụ thuộc:

CPPFLAGS += -MD -MP                                         
SRC = $(wildcard *.cpp)                                                       

my_executable: $(SRC:%.cpp=%.o)                                                        
        g++ $(LDFLAGS) -o $@ $^                                               

-include $(SRC:%.cpp=%.d)

Đây là một bài đăng blog thảo luận sâu hơn về nó: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html


6

-Werror, coi tất cả các cảnh báo là lỗi và dừng quá trình biên dịch. Các gcctrang hướng dẫn giải thích mỗi dòng lệnh chuyển đổi cho trình biên dịch của bạn.


@Matt Joiner: Vì bạn không đề cập đến kiến ​​trúc máy nào bạn đang sử dụng, các gcccờ có thể khác nhau giữa bạn và bất kỳ liên kết nào mà bất kỳ ai có thể đề xuất. Đây là lý do tại sao các trang hướng dẫn được cung cấp với phần mềm của bạn.
Greg Hewgill

4

-Wfloat-equal

Từ: http://mces.blogspot.com/2005/07/char-const-argv.html

Một trong những cảnh báo mới khác mà tôi thích là -Wfloat-bằng. Điều đó cảnh báo bất cứ khi nào bạn [có] số dấu phẩy động trong điều kiện đẳng thức. Thật rực rỡ! Nếu bạn đã từng lập trình một đồ họa máy tính hoặc (tệ hơn :) thuật toán hình học tính toán, bạn sẽ biết rằng không có hai số float nào khớp với đẳng thức ...


10
Nổi của tôi làm phù hợp với bình đẳng, như tôi biết những gì tôi đang làm.
Roland Illig

4

Tôi tìm thấy chủ đề này đang tìm kiếm một lá cờ để khắc phục một vấn đề cụ thể, tôi không thấy nó ở đây vì vậy tôi sẽ thêm một chủ đề vừa ném tôi vào bài viết của mình :

các -Wformat=2cờ

-Wformat=> Kiểm tra các cuộc gọi đến printfscanf, v.v., để đảm bảo rằng các đối số được cung cấp có loại phù hợp với chuỗi định dạng được chỉ định ...

Và phần thực sự quan trọng về nó ( theo hướng dẫn của GCC ):

-Wformatđược bao gồm trong -Wall. Đối với kiểm soát nhiều hơn một số khía cạnh của định dạng kiểm tra, các tùy chọn -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, và -Wformat=2có sẵn, nhưng không bao gồm trong -Wall.`

Vì vậy, chỉ vì bạn -Wallkhông có nghĩa là bạn có tất cả. ;)


3

Đôi khi tôi sử dụng -scho một thực thi nhỏ hơn nhiều:

-s
    Remove all symbol table and relocation information from the executable.

Nguồn: http://gcc.gnu.org/onlinesocs/gcc/Link-Options.html#Link-Options


6
bạn chỉ nên chạy striptrên tệp nhị phân của mình, bằng cách này bạn có thể có tệp nhị phân với thông tin gỡ lỗi, xóa nó sau để phân phối.
Hasturkun

Vâng, stripcũng hoạt động nhưng -scó thể nhanh hơn và dễ dàng hơn, mặc dù nó không phức tạp như chạystrip
Vasiliy Sharapov

3

Mặc dù câu trả lời này có thể hơi lạc đề và câu hỏi là +1 xứng đáng với tôi, vì

Tôi đặc biệt quan tâm đến bất kỳ cảnh báo bổ sung nào, và / hoặc biến cảnh báo thành lỗi trong một số trường hợp để giảm thiểu tuyệt đối mọi trường hợp không phù hợp.
có một công cụ giúp loại bỏ TẤT CẢ các lỗi và các lỗi tiềm ẩn có thể không rõ ràng, có nẹp mà IMHO thực hiện công việc tốt hơn trong việc tìm ra các lỗi so với gcc hoặc bất kỳ trình biên dịch nào khác cho vấn đề đó. Đó là một công cụ xứng đáng để có trong rương công cụ của bạn.

Kiểm tra tĩnh thông qua một loại công cụ lint như nẹp, nên là một phần của chuỗi công cụ biên dịch.


Nó luôn hiển thị lỗi không thể gửi tệp tiền xử lý trong C: \ bao gồm, tôi không chắc phải làm gì
Suraj Jain

2

Tôi đặc biệt quan tâm đến bất kỳ cảnh báo bổ sung nào,

Ngoài ra -Wall, tùy chọn -Whoặc -Wextra( -Whoạt động với các phiên bản cũ hơn của gcc cũng như các phiên bản mới hơn; các phiên bản gần đây hơn hỗ trợ tên thay thế -Wextra, có nghĩa tương tự, nhưng mô tả nhiều hơn) cho phép cảnh báo bổ sung khác nhau.

Thậm chí còn có nhiều cảnh báo không được kích hoạt bởi một trong hai cảnh báo, nói chung đối với những điều tồi tệ hơn. Tập hợp các tùy chọn khả dụng phụ thuộc vào phiên bản gcc bạn đang sử dụng - tham khảo man gcchoặc info gccđể biết chi tiết hoặc xem tài liệu trực tuyến cho phiên bản gcc cụ thể mà bạn quan tâm. Và -pedanticđưa ra tất cả các cảnh báo theo tiêu chuẩn cụ thể đang sử dụng (tùy thuộc vào trên các tùy chọn khác như -std=xxxhoặc -ansi) và phàn nàn về việc sử dụng các tiện ích mở rộng gcc.

và / hoặc biến cảnh báo thành lỗi trong một số trường hợp để giảm thiểu tuyệt đối mọi trường hợp không phù hợp.

-Werrorbiến tất cả các cảnh báo thành lỗi. Tôi không nghĩ rằng gcc cho phép bạn làm điều đó một cách chọn lọc cho các cảnh báo cụ thể, mặc dù.

Bạn có thể thấy rằng bạn phải chọn lọc về những cảnh báo nào được bật trên cơ sở từng dự án (đặc biệt là nếu bạn sử dụng -Werror), vì các tệp tiêu đề từ các thư viện bên ngoài có thể vấp phải một số trong số chúng. (-pedantic đặc biệt có xu hướng không có ích trong khía cạnh này, theo kinh nghiệm của tôi.)


4
"Tôi không nghĩ rằng gcc cho phép bạn làm điều đó một cách chọn lọc cho các cảnh báo cụ thể, mặc dù." Trên thực tế, bạn có thể với -Werror=some-warning.
Matthew Flaschen

0
  • -Wmissing-prototypes: Nếu một hàm toàn cục được xác định mà không có khai báo nguyên mẫu trước đó.
  • -Wformat-security: Cảnh báo về việc sử dụng các chức năng định dạng đại diện cho các vấn đề bảo mật có thể xảy ra. Hiện tại, điều này cảnh báo về các lệnh gọi printfvà các scanfhàm trong đó chuỗi định dạng không phải là một chuỗi ký tự và không có đối số định dạng

0
  • -Werror=return-type: Thực thi lỗi khi hàm không có return trong gcc. Đó là /we4716trong Visual Studio.

  • -Werror=implicit-function-declaration: Thực thi lỗi khi chức năng được sử dụng mà không được xác định / không bao gồm. Đó là /we4013trong Visual Studio.

  • -Werror=incompatible-pointer-types: Lỗi xảy ra khi loại con trỏ không khớp với loại con trỏ dự kiến. Đó là /we4133trong Visual Studio.

Trên thực tế, tôi muốn giữ nền tảng mã C của mình và tôi sử dụng CMake và tôi đặt các đoạn mã được cung cấp vào CMakeLists.txt như:

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013 /we4133 /we4716")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=return-type")
endif()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.