PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
PVS-ಸ್ಟುಡಿಯೋ ವಿಶ್ಲೇಷಕವನ್ನು ಬಳಸುವ ಅತ್ಯಂತ ಪ್ರಸ್ತುತ ಸನ್ನಿವೇಶಗಳಲ್ಲಿ ಒಂದಾಗಿದೆ CI ವ್ಯವಸ್ಥೆಗಳೊಂದಿಗೆ ಅದರ ಏಕೀಕರಣ. ಮತ್ತು ಯಾವುದೇ ನಿರಂತರ ಏಕೀಕರಣ ವ್ಯವಸ್ಥೆಯಿಂದ PVS-ಸ್ಟುಡಿಯೋ ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆಯನ್ನು ಕೆಲವೇ ಆಜ್ಞೆಗಳಲ್ಲಿ ನಿರ್ಮಿಸಬಹುದಾದರೂ, ನಾವು ಈ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಇನ್ನಷ್ಟು ಅನುಕೂಲಕರವಾಗಿ ಮಾಡುವುದನ್ನು ಮುಂದುವರಿಸುತ್ತೇವೆ. PVS-ಸ್ಟುಡಿಯೋ ಈಗ ಟೀಮ್‌ಸಿಟಿ - ಟೀಮ್‌ಸಿಟಿ ತಪಾಸಣೆ ಪ್ರಕಾರಕ್ಕೆ ವಿಶ್ಲೇಷಕದ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಫಾರ್ಮ್ಯಾಟ್‌ಗೆ ಪರಿವರ್ತಿಸಲು ಬೆಂಬಲವನ್ನು ಹೊಂದಿದೆ. ಅದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ ಎಂದು ನೋಡೋಣ.

ಬಳಸಿದ ಸಾಫ್ಟ್‌ವೇರ್ ಬಗ್ಗೆ ಮಾಹಿತಿ

ಪಿವಿಎಸ್-ಸ್ಟುಡಿಯೋ - C, C++, C# ಮತ್ತು Java ಕೋಡ್‌ನ ಸ್ಥಿರ ವಿಶ್ಲೇಷಕ, ವಿವಿಧ ರೀತಿಯ ದೋಷಗಳನ್ನು ಹುಡುಕುವ ಮತ್ತು ಸರಿಪಡಿಸುವ ಕಾರ್ಯವನ್ನು ಸುಲಭಗೊಳಿಸಲು ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದೆ. ವಿಶ್ಲೇಷಕವನ್ನು ವಿಂಡೋಸ್, ಲಿನಕ್ಸ್ ಮತ್ತು ಮ್ಯಾಕೋಸ್‌ನಲ್ಲಿ ಬಳಸಬಹುದು. ಈ ಲೇಖನದಲ್ಲಿ ನಾವು ವಿಶ್ಲೇಷಕವನ್ನು ಮಾತ್ರ ಸಕ್ರಿಯವಾಗಿ ಬಳಸುತ್ತೇವೆ, ಆದರೆ ಅದರ ವಿತರಣೆಯಿಂದ ಕೆಲವು ಉಪಯುಕ್ತತೆಗಳನ್ನು ಸಹ ಬಳಸುತ್ತೇವೆ.

CLMonitor — ಇದು ಕಂಪೈಲರ್ ಉಡಾವಣೆಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡುವ ಮಾನಿಟರಿಂಗ್ ಸರ್ವರ್ ಆಗಿದೆ. ನಿಮ್ಮ ಯೋಜನೆಯನ್ನು ನಿರ್ಮಿಸಲು ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು ಅದನ್ನು ತಕ್ಷಣವೇ ಚಲಾಯಿಸಬೇಕು. ಸ್ನೂಪಿಂಗ್ ಮೋಡ್‌ನಲ್ಲಿ, ಸರ್ವರ್ ಎಲ್ಲಾ ಬೆಂಬಲಿತ ಕಂಪೈಲರ್‌ಗಳ ರನ್‌ಗಳನ್ನು ಪ್ರತಿಬಂಧಿಸುತ್ತದೆ. ಈ ಉಪಯುಕ್ತತೆಯನ್ನು C/C++ ಯೋಜನೆಗಳನ್ನು ವಿಶ್ಲೇಷಿಸಲು ಮಾತ್ರ ಬಳಸಬಹುದೆಂದು ಗಮನಿಸಬೇಕಾದ ಅಂಶವಾಗಿದೆ.

ಪ್ಲೋಗ್ ಪರಿವರ್ತಕ - ವಿಶ್ಲೇಷಕ ವರದಿಗಳನ್ನು ವಿವಿಧ ಸ್ವರೂಪಗಳಿಗೆ ಪರಿವರ್ತಿಸುವ ಉಪಯುಕ್ತತೆ.

ಅಧ್ಯಯನದ ಅಡಿಯಲ್ಲಿ ಯೋಜನೆಯ ಬಗ್ಗೆ ಮಾಹಿತಿ

ಪ್ರಾಯೋಗಿಕ ಉದಾಹರಣೆಯಲ್ಲಿ ಈ ಕಾರ್ಯವನ್ನು ಪ್ರಯತ್ನಿಸೋಣ - ನಾವು OpenRCT2 ಯೋಜನೆಯನ್ನು ವಿಶ್ಲೇಷಿಸೋಣ.

ಓಪನ್ಆರ್ಸಿಟಿ 2 - ಆಟದ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 (RCT2) ನ ಮುಕ್ತ ಅನುಷ್ಠಾನ, ಅದನ್ನು ಹೊಸ ಕಾರ್ಯಗಳೊಂದಿಗೆ ವಿಸ್ತರಿಸುವುದು ಮತ್ತು ದೋಷಗಳನ್ನು ಸರಿಪಡಿಸುವುದು. ಆಟವು ಸವಾರಿಗಳು, ಅಂಗಡಿಗಳು ಮತ್ತು ಸೌಲಭ್ಯಗಳನ್ನು ಒಳಗೊಂಡಿರುವ ಮನೋರಂಜನಾ ಉದ್ಯಾನವನವನ್ನು ನಿರ್ಮಿಸುವುದು ಮತ್ತು ನಿರ್ವಹಿಸುವುದರ ಸುತ್ತ ಸುತ್ತುತ್ತದೆ. ಆಟಗಾರನು ಲಾಭವನ್ನು ಗಳಿಸಲು ಪ್ರಯತ್ನಿಸಬೇಕು ಮತ್ತು ಅತಿಥಿಗಳನ್ನು ಸಂತೋಷವಾಗಿರಿಸುವಾಗ ಉದ್ಯಾನದ ಉತ್ತಮ ಖ್ಯಾತಿಯನ್ನು ಕಾಪಾಡಿಕೊಳ್ಳಬೇಕು. OpenRCT2 ನಿಮಗೆ ಸನ್ನಿವೇಶ ಮತ್ತು ಸ್ಯಾಂಡ್‌ಬಾಕ್ಸ್ ಎರಡರಲ್ಲೂ ಆಡಲು ಅನುಮತಿಸುತ್ತದೆ. ಸನ್ನಿವೇಶಗಳು ನಿರ್ದಿಷ್ಟ ಕಾರ್ಯವನ್ನು ನಿಗದಿತ ಸಮಯದೊಳಗೆ ಪೂರ್ಣಗೊಳಿಸಲು ಆಟಗಾರನಿಗೆ ಅಗತ್ಯವಿರುತ್ತದೆ, ಆದರೆ ಸ್ಯಾಂಡ್‌ಬಾಕ್ಸ್ ಆಟಗಾರನಿಗೆ ಯಾವುದೇ ನಿರ್ಬಂಧಗಳು ಅಥವಾ ಹಣಕಾಸು ಇಲ್ಲದೆ ಹೆಚ್ಚು ಹೊಂದಿಕೊಳ್ಳುವ ಉದ್ಯಾನವನವನ್ನು ನಿರ್ಮಿಸಲು ಅನುಮತಿಸುತ್ತದೆ.

ಹೊಂದಾಣಿಕೆ

ಸಮಯವನ್ನು ಉಳಿಸಲು, ನಾನು ಬಹುಶಃ ಅನುಸ್ಥಾಪನ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಬಿಟ್ಟುಬಿಡುತ್ತೇನೆ ಮತ್ತು ನನ್ನ ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿ ಟೀಮ್‌ಸಿಟಿ ಸರ್ವರ್ ಚಾಲನೆಯಲ್ಲಿರುವ ಕ್ಷಣದಿಂದ ಪ್ರಾರಂಭಿಸುತ್ತೇನೆ. ನಾವು ಇಲ್ಲಿಗೆ ಹೋಗಬೇಕಾಗಿದೆ: ಲೋಕಲ್ ಹೋಸ್ಟ್:{ಸ್ಥಾಪನಾ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಿದ ಪೋರ್ಟ್} (ನನ್ನ ಸಂದರ್ಭದಲ್ಲಿ, ಲೋಕಲ್ ಹೋಸ್ಟ್:9090) ಮತ್ತು ದೃಢೀಕರಣ ಡೇಟಾವನ್ನು ನಮೂದಿಸಿ. ಪ್ರವೇಶಿಸಿದ ನಂತರ ನಮ್ಮನ್ನು ಸ್ವಾಗತಿಸಲಾಗುತ್ತದೆ:

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಕ್ರಿಯೇಟ್ ಪ್ರಾಜೆಕ್ಟ್ ಬಟನ್ ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ. ಮುಂದೆ, ಹಸ್ತಚಾಲಿತವಾಗಿ ಆಯ್ಕೆಮಾಡಿ ಮತ್ತು ಕ್ಷೇತ್ರಗಳನ್ನು ಭರ್ತಿ ಮಾಡಿ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಗುಂಡಿಯನ್ನು ಒತ್ತಿದ ನಂತರ ರಚಿಸಿ, ಸೆಟ್ಟಿಂಗ್‌ಗಳೊಂದಿಗೆ ವಿಂಡೋ ಮೂಲಕ ನಮ್ಮನ್ನು ಸ್ವಾಗತಿಸಲಾಗುತ್ತದೆ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಕ್ಲಿಕ್ ಮಾಡೋಣ ನಿರ್ಮಾಣ ಸಂರಚನೆಯನ್ನು ರಚಿಸಿ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಕ್ಷೇತ್ರಗಳನ್ನು ಭರ್ತಿ ಮಾಡಿ ಮತ್ತು ಕ್ಲಿಕ್ ಮಾಡಿ ರಚಿಸಿ. ಆವೃತ್ತಿ ನಿಯಂತ್ರಣ ವ್ಯವಸ್ಥೆಯನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳುವ ವಿಂಡೋವನ್ನು ನಾವು ನೋಡುತ್ತೇವೆ. ಮೂಲಗಳು ಈಗಾಗಲೇ ಸ್ಥಳೀಯವಾಗಿ ನೆಲೆಗೊಂಡಿರುವುದರಿಂದ, ಕ್ಲಿಕ್ ಮಾಡಿ ಸ್ಕಿಪ್.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಅಂತಿಮವಾಗಿ, ನಾವು ಯೋಜನೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗುತ್ತೇವೆ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಜೋಡಣೆ ಹಂತಗಳನ್ನು ಸೇರಿಸೋಣ, ಇದನ್ನು ಮಾಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ: ಹಂತಗಳನ್ನು ನಿರ್ಮಿಸಿ -> ನಿರ್ಮಾಣ ಹಂತವನ್ನು ಸೇರಿಸಿ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಇಲ್ಲಿ ನಾವು ಆಯ್ಕೆ ಮಾಡುತ್ತೇವೆ:

  • ರನ್ನರ್ ಪ್ರಕಾರ -> ಕಮಾಂಡ್ ಲೈನ್
  • ರನ್ -> ಕಸ್ಟಮ್ ಸ್ಕ್ರಿಪ್ಟ್

ಪ್ರಾಜೆಕ್ಟ್ ಸಂಕಲನದ ಸಮಯದಲ್ಲಿ ನಾವು ವಿಶ್ಲೇಷಣೆ ಮಾಡುವುದರಿಂದ, ಜೋಡಣೆ ಮತ್ತು ವಿಶ್ಲೇಷಣೆ ಒಂದು ಹಂತವಾಗಿರಬೇಕು, ಆದ್ದರಿಂದ ಕ್ಷೇತ್ರವನ್ನು ಭರ್ತಿ ಮಾಡಿ ಕಸ್ಟಮ್ ಸ್ಕ್ರಿಪ್ಟ್:

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ನಾವು ನಂತರ ಪ್ರತ್ಯೇಕ ಹಂತಗಳನ್ನು ನೋಡುತ್ತೇವೆ. ವಿಶ್ಲೇಷಕವನ್ನು ಲೋಡ್ ಮಾಡುವುದು, ಯೋಜನೆಯನ್ನು ಜೋಡಿಸುವುದು, ಅದನ್ನು ವಿಶ್ಲೇಷಿಸುವುದು, ವರದಿಯನ್ನು ಔಟ್ಪುಟ್ ಮಾಡುವುದು ಮತ್ತು ಅದನ್ನು ಫಾರ್ಮ್ಯಾಟ್ ಮಾಡುವುದು ಕೇವಲ ಹನ್ನೊಂದು ಸಾಲುಗಳ ಕೋಡ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ.

ನಾವು ಮಾಡಬೇಕಾದ ಕೊನೆಯ ವಿಷಯವೆಂದರೆ ಪರಿಸರದ ಅಸ್ಥಿರಗಳನ್ನು ಹೊಂದಿಸುವುದು, ಅವುಗಳ ಓದುವಿಕೆಯನ್ನು ಸುಧಾರಿಸಲು ನಾನು ಕೆಲವು ಮಾರ್ಗಗಳನ್ನು ವಿವರಿಸಿದ್ದೇನೆ. ಇದನ್ನು ಮಾಡಲು, ನಾವು ಮುಂದುವರಿಯೋಣ: ನಿಯತಾಂಕಗಳು -> ಹೊಸ ನಿಯತಾಂಕವನ್ನು ಸೇರಿಸಿ ಮತ್ತು ಮೂರು ಅಸ್ಥಿರಗಳನ್ನು ಸೇರಿಸಿ:

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ನೀವು ಮಾಡಬೇಕಾಗಿರುವುದು ಗುಂಡಿಯನ್ನು ಒತ್ತಿ ರನ್ ಮೇಲಿನ ಬಲ ಮೂಲೆಯಲ್ಲಿ. ಯೋಜನೆಯನ್ನು ಜೋಡಿಸಿ ಮತ್ತು ವಿಶ್ಲೇಷಿಸುತ್ತಿರುವಾಗ, ನಾನು ಸ್ಕ್ರಿಪ್ಟ್ ಬಗ್ಗೆ ಹೇಳುತ್ತೇನೆ.

ನೇರವಾಗಿ ಸ್ಕ್ರಿಪ್ಟ್

ಮೊದಲಿಗೆ, ನಾವು ಇತ್ತೀಚಿನ PVS-ಸ್ಟುಡಿಯೋ ವಿತರಣೆಯನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಬೇಕಾಗಿದೆ. ಇದಕ್ಕಾಗಿ ನಾವು ಚಾಕೊಲೇಟಿ ಪ್ಯಾಕೇಜ್ ಮ್ಯಾನೇಜರ್ ಅನ್ನು ಬಳಸುತ್ತೇವೆ. ಇದರ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ತಿಳಿದುಕೊಳ್ಳಲು ಬಯಸುವವರಿಗೆ, ಅನುರೂಪವಾಗಿದೆ ಲೇಖನ:

choco install pvs-studio -y

ಮುಂದೆ, CLMonitor ಪ್ರಾಜೆಕ್ಟ್ ಬಿಲ್ಡ್ ಟ್ರ್ಯಾಕಿಂಗ್ ಉಪಯುಕ್ತತೆಯನ್ನು ಪ್ರಾರಂಭಿಸೋಣ.

%CLmon% monitor –-attach

ನಂತರ ನಾವು ಯೋಜನೆಯನ್ನು ಪರಿಸರ ವೇರಿಯಬಲ್ ಆಗಿ ನಿರ್ಮಿಸುತ್ತೇವೆ ಎಂ.ಎಸ್.ಬಿ. ನಾನು ನಿರ್ಮಿಸಬೇಕಾದ MSBuild ನ ಆವೃತ್ತಿಯ ಮಾರ್ಗವಾಗಿದೆ

%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable

PVS-ಸ್ಟುಡಿಯೋಗಾಗಿ ಲಾಗಿನ್ ಮತ್ತು ಪರವಾನಗಿ ಕೀಲಿಯನ್ನು ನಮೂದಿಸೋಣ:

%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%

ನಿರ್ಮಾಣ ಪೂರ್ಣಗೊಂಡ ನಂತರ, ಪೂರ್ವ-ಸಂಸ್ಕರಿಸಿದ ಫೈಲ್‌ಗಳು ಮತ್ತು ಸ್ಥಿರ ವಿಶ್ಲೇಷಣೆಯನ್ನು ರಚಿಸಲು CLMonitor ಅನ್ನು ಮತ್ತೆ ಚಲಾಯಿಸಿ:

%CLmon% analyze -l "c:ptest.plog"

ನಂತರ ನಾವು ನಮ್ಮ ವಿತರಣೆಯಿಂದ ಮತ್ತೊಂದು ಉಪಯುಕ್ತತೆಯನ್ನು ಬಳಸುತ್ತೇವೆ. PlogConverter ವರದಿಯನ್ನು ಪ್ರಮಾಣಿತ ಸ್ವರೂಪದಿಂದ TeamCity-ನಿರ್ದಿಷ್ಟ ಸ್ವರೂಪಕ್ಕೆ ಪರಿವರ್ತಿಸುತ್ತದೆ. ಇದಕ್ಕೆ ಧನ್ಯವಾದಗಳು, ನಾವು ಅದನ್ನು ನೇರವಾಗಿ ಬಿಲ್ಡ್ ವಿಂಡೋದಲ್ಲಿ ವೀಕ್ಷಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ.

%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"

ಫಾರ್ಮ್ಯಾಟ್ ಮಾಡಿದ ವರದಿಯನ್ನು ಪ್ರದರ್ಶಿಸುವುದು ಕೊನೆಯ ಹಂತವಾಗಿದೆ stdout, ಅಲ್ಲಿ ಟೀಮ್‌ಸಿಟಿ ಪಾರ್ಸರ್ ಮೂಲಕ ಅದನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತದೆ.

type "C:tempptest.plog_TeamCity.txt"

ಪೂರ್ಣ ಸ್ಕ್ರಿಪ್ಟ್ ಕೋಡ್:

choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"

ಈ ಮಧ್ಯೆ, ಯೋಜನೆಯ ಜೋಡಣೆ ಮತ್ತು ವಿಶ್ಲೇಷಣೆ ಯಶಸ್ವಿಯಾಗಿ ಪೂರ್ಣಗೊಂಡಿದೆ, ನಾವು ಟ್ಯಾಬ್ಗೆ ಹೋಗಬಹುದು ಯೋಜನೆಗಳು ಮತ್ತು ಅದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಈಗ ಕ್ಲಿಕ್ ಮಾಡೋಣ ಒಟ್ಟು ತಪಾಸಣೆವಿಶ್ಲೇಷಕ ವರದಿಯನ್ನು ವೀಕ್ಷಿಸಲು ಹೋಗಲು:

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ಎಚ್ಚರಿಕೆಗಳನ್ನು ರೋಗನಿರ್ಣಯದ ನಿಯಮ ಸಂಖ್ಯೆಗಳ ಮೂಲಕ ಗುಂಪು ಮಾಡಲಾಗಿದೆ. ಕೋಡ್ ಮೂಲಕ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು, ನೀವು ಎಚ್ಚರಿಕೆಯೊಂದಿಗೆ ಸಾಲಿನ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಕ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ. ಮೇಲಿನ ಬಲ ಮೂಲೆಯಲ್ಲಿರುವ ಪ್ರಶ್ನಾರ್ಥಕ ಚಿಹ್ನೆಯ ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡುವುದರಿಂದ ನಿಮಗೆ ದಾಖಲೆಯೊಂದಿಗೆ ಹೊಸ ಟ್ಯಾಬ್ ತೆರೆಯುತ್ತದೆ. ವಿಶ್ಲೇಷಕದ ಎಚ್ಚರಿಕೆಯೊಂದಿಗೆ ಸಾಲಿನ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಕ್ ಮಾಡುವ ಮೂಲಕ ನೀವು ಕೋಡ್ ಮೂಲಕ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಬಹುದು. ಬಳಸುವಾಗ ರಿಮೋಟ್ ಕಂಪ್ಯೂಟರ್ನಿಂದ ನ್ಯಾವಿಗೇಷನ್ ಸಾಧ್ಯವಿದೆ SourceTreeRoot ಮಾರ್ಕರ್. ವಿಶ್ಲೇಷಕದ ಈ ಕಾರ್ಯಾಚರಣೆಯ ವಿಧಾನದಲ್ಲಿ ಆಸಕ್ತಿ ಹೊಂದಿರುವ ಯಾರಾದರೂ ಅನುಗುಣವಾದ ವಿಭಾಗದೊಂದಿಗೆ ತಮ್ಮನ್ನು ಪರಿಚಯಿಸಿಕೊಳ್ಳಬಹುದು ದಸ್ತಾವೇಜನ್ನು.

ವಿಶ್ಲೇಷಕದ ಫಲಿತಾಂಶಗಳನ್ನು ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ

ಈಗ ನಾವು ಬಿಲ್ಡ್ ಅನ್ನು ನಿಯೋಜಿಸುವುದನ್ನು ಮತ್ತು ಕಾನ್ಫಿಗರ್ ಮಾಡುವುದನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೇವೆ, ನಾವು ನೋಡುತ್ತಿರುವ ಯೋಜನೆಯಲ್ಲಿ ಕಂಡುಬರುವ ಕೆಲವು ಆಸಕ್ತಿದಾಯಕ ಎಚ್ಚರಿಕೆಗಳನ್ನು ನೋಡೋಣ.

ಎಚ್ಚರಿಕೆ N1

V773 [CWE-401] 'ಫಲಿತಾಂಶ' ಪಾಯಿಂಟರ್ ಅನ್ನು ಬಿಡುಗಡೆ ಮಾಡದೆಯೇ ವಿನಾಯಿತಿಯನ್ನು ಎಸೆಯಲಾಯಿತು. ಮೆಮೊರಿ ಸೋರಿಕೆ ಸಾಧ್ಯ. libopenrct2 ObjectFactory.cpp 443

Object* CreateObjectFromJson(....)
{
  Object* result = nullptr;
  ....
  result = CreateObject(entry);
  ....
  if (readContext.WasError())
  {
    throw std::runtime_error("Object has errors");
  }
  ....
}

Object* CreateObject(const rct_object_entry& entry)
{
  Object* result;
  switch (entry.GetType())
  {
    case OBJECT_TYPE_RIDE:
      result = new RideObject(entry);
      break;
    case OBJECT_TYPE_SMALL_SCENERY:
      result = new SmallSceneryObject(entry);
      break;
    case OBJECT_TYPE_LARGE_SCENERY:
      result = new LargeSceneryObject(entry);
      break;
    ....
    default:
      throw std::runtime_error("Invalid object type");
  }
  return result;
}

ಮೆಮೊರಿಯನ್ನು ಕ್ರಿಯಾತ್ಮಕವಾಗಿ ನಿಯೋಜಿಸಿದ ನಂತರ ದೋಷವನ್ನು ವಿಶ್ಲೇಷಕ ಗಮನಿಸಿದೆ ವಸ್ತುವನ್ನು ರಚಿಸಿ, ವಿನಾಯಿತಿ ಸಂಭವಿಸಿದಾಗ, ಮೆಮೊರಿಯನ್ನು ತೆರವುಗೊಳಿಸಲಾಗುವುದಿಲ್ಲ ಮತ್ತು ಮೆಮೊರಿ ಸೋರಿಕೆ ಸಂಭವಿಸುತ್ತದೆ.

ಎಚ್ಚರಿಕೆ N2

V501 '|' ನ ಎಡಕ್ಕೆ ಮತ್ತು ಬಲಕ್ಕೆ '(1ULL << WIDX_MONTH_BOX)' ಒಂದೇ ರೀತಿಯ ಉಪ-ಅಭಿವ್ಯಕ್ತಿಗಳಿವೆ. ಆಪರೇಟರ್. libopenrct2ui Cheats.cpp 487

static uint64_t window_cheats_page_enabled_widgets[] = 
{
  MAIN_CHEAT_ENABLED_WIDGETS |
  (1ULL << WIDX_NO_MONEY) |
  (1ULL << WIDX_ADD_SET_MONEY_GROUP) |
  (1ULL << WIDX_MONEY_SPINNER) |
  (1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
  (1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
  (1ULL << WIDX_ADD_MONEY) |
  (1ULL << WIDX_SET_MONEY) |
  (1ULL << WIDX_CLEAR_LOAN) |
  (1ULL << WIDX_DATE_SET) |
  (1ULL << WIDX_MONTH_BOX) |  // <=
  (1ULL << WIDX_MONTH_UP) |
  (1ULL << WIDX_MONTH_DOWN) |
  (1ULL << WIDX_YEAR_BOX) |
  (1ULL << WIDX_YEAR_UP) |
  (1ULL << WIDX_YEAR_DOWN) |
  (1ULL << WIDX_DAY_BOX) |
  (1ULL << WIDX_DAY_UP) |
  (1ULL << WIDX_DAY_DOWN) |
  (1ULL << WIDX_MONTH_BOX) |  // <=
  (1ULL << WIDX_DATE_GROUP) |
  (1ULL << WIDX_DATE_RESET),
  ....
};

ಸ್ಥಿರ ವಿಶ್ಲೇಷಕವನ್ನು ಹೊರತುಪಡಿಸಿ ಕೆಲವು ಜನರು ಈ ಗಮನಿಸುವಿಕೆ ಪರೀಕ್ಷೆಯಲ್ಲಿ ಉತ್ತೀರ್ಣರಾಗಬಹುದು. ಈ ಕಾಪಿ-ಪೇಸ್ಟ್ ಉದಾಹರಣೆಯು ನಿಖರವಾಗಿ ಈ ಕಾರಣಕ್ಕಾಗಿ ಉತ್ತಮವಾಗಿದೆ.

ಎಚ್ಚರಿಕೆಗಳು N3

V703 ಪಡೆದ ವರ್ಗ 'RCT12BannerElement' ನಲ್ಲಿನ 'ಫ್ಲ್ಯಾಗ್ಸ್' ಕ್ಷೇತ್ರವು ಬೇಸ್ ಕ್ಲಾಸ್ 'RCT12TileElementBase' ನಲ್ಲಿ ಕ್ಷೇತ್ರವನ್ನು ಓವರ್‌ರೈಟ್ ಮಾಡುವುದು ವಿಚಿತ್ರವಾಗಿದೆ. ಸಾಲುಗಳನ್ನು ಪರಿಶೀಲಿಸಿ: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

struct RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};
struct rct1_peep : RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};

ಸಹಜವಾಗಿ, ಮೂಲ ವರ್ಗದಲ್ಲಿ ಮತ್ತು ಸಂತತಿಯಲ್ಲಿ ಅದೇ ಹೆಸರಿನೊಂದಿಗೆ ವೇರಿಯೇಬಲ್ ಅನ್ನು ಬಳಸುವುದು ಯಾವಾಗಲೂ ದೋಷವಲ್ಲ. ಆದಾಗ್ಯೂ, ಆನುವಂಶಿಕ ತಂತ್ರಜ್ಞಾನವು ಪೋಷಕರ ವರ್ಗದ ಎಲ್ಲಾ ಕ್ಷೇತ್ರಗಳು ಮಕ್ಕಳ ವರ್ಗದಲ್ಲಿದೆ ಎಂದು ಊಹಿಸುತ್ತದೆ. ಉತ್ತರಾಧಿಕಾರಿಯಲ್ಲಿ ಅದೇ ಹೆಸರಿನ ಕ್ಷೇತ್ರಗಳನ್ನು ಘೋಷಿಸುವ ಮೂಲಕ, ನಾವು ಗೊಂದಲವನ್ನು ಸೃಷ್ಟಿಸುತ್ತೇವೆ.

ಎಚ್ಚರಿಕೆ N4

V793 'imageDirection / 8' ಹೇಳಿಕೆಯ ಫಲಿತಾಂಶವು ಸ್ಥಿತಿಯ ಒಂದು ಭಾಗವಾಗಿದೆ ಎಂಬುದು ಬೆಸವಾಗಿದೆ. ಬಹುಶಃ, ಈ ಹೇಳಿಕೆಯನ್ನು ಬೇರೆ ಯಾವುದನ್ನಾದರೂ ಹೋಲಿಸಬೇಕು. libopenrct2 ObservationTower.cpp 38

void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
  if ((imageDirection / 8) && (imageDirection / 8) != 3)
  {
    ....
  }
  ....
}

ಹತ್ತಿರದಿಂದ ನೋಡೋಣ. ಅಭಿವ್ಯಕ್ತಿ ಚಿತ್ರ ನಿರ್ದೇಶನ/8 ಇದ್ದರೆ ಸುಳ್ಳಾಗುತ್ತದೆ ಚಿತ್ರ ನಿರ್ದೇಶನ -7 ರಿಂದ 7 ರವರೆಗಿನ ವ್ಯಾಪ್ತಿಯಲ್ಲಿದೆ. ಎರಡನೇ ಭಾಗ: (ಚಿತ್ರ ನಿರ್ದೇಶನ / 8) != 3 ಪರಿಶೀಲಿಸುತ್ತದೆ ಚಿತ್ರ ನಿರ್ದೇಶನ ವ್ಯಾಪ್ತಿಯ ಹೊರಗಿದ್ದಕ್ಕಾಗಿ: ಕ್ರಮವಾಗಿ -31 ರಿಂದ -24 ಮತ್ತು 24 ರಿಂದ 31 ರವರೆಗೆ. ಈ ರೀತಿಯಾಗಿ ನಿರ್ದಿಷ್ಟ ಶ್ರೇಣಿಯಲ್ಲಿ ಸೇರ್ಪಡೆಗಾಗಿ ಸಂಖ್ಯೆಗಳನ್ನು ಪರಿಶೀಲಿಸುವುದು ನನಗೆ ತುಂಬಾ ವಿಚಿತ್ರವಾಗಿ ತೋರುತ್ತದೆ ಮತ್ತು ಈ ಕೋಡ್‌ನಲ್ಲಿ ಯಾವುದೇ ದೋಷವಿಲ್ಲದಿದ್ದರೂ ಸಹ, ಈ ಷರತ್ತುಗಳನ್ನು ಹೆಚ್ಚು ಸ್ಪಷ್ಟವಾಗಿರಲು ನಾನು ಮತ್ತೆ ಬರೆಯಲು ಶಿಫಾರಸು ಮಾಡುತ್ತೇವೆ. ಈ ಕೋಡ್ ಅನ್ನು ಓದುವ ಮತ್ತು ನಿರ್ವಹಿಸುವ ಜನರಿಗೆ ಇದು ಜೀವನವನ್ನು ಹೆಚ್ಚು ಸುಲಭಗೊಳಿಸುತ್ತದೆ.

ಎಚ್ಚರಿಕೆ N5

V587 ಈ ರೀತಿಯ ಅಸೈನ್‌ಮೆಂಟ್‌ಗಳ ಬೆಸ ಅನುಕ್ರಮ: A = B; ಬಿ = ಎ;. ಸಾಲುಗಳನ್ನು ಪರಿಶೀಲಿಸಿ: 1115, 1118. libopenrct2ui MouseInput.cpp 1118

void process_mouse_over(....)
{
  ....
  switch (window->widgets[widgetId].type)
  {
    case WWT_VIEWPORT:
      ebx = 0;
      edi = cursorId;                                 // <=
      // Window event WE_UNKNOWN_0E was called here,
      // but no windows actually implemented a handler and
      // it's not known what it was for
      cursorId = edi;                                 // <=
      if ((ebx & 0xFF) != 0)
      {
        set_cursor(cursorId);
        return;
      }
      break;
      ....
  }
  ....
}

ಈ ಕೋಡ್ ತುಣುಕನ್ನು ಹೆಚ್ಚಾಗಿ ವಿಘಟನೆಯ ಮೂಲಕ ಪಡೆಯಲಾಗಿದೆ. ನಂತರ, ಬಿಟ್ಟ ಕಾಮೆಂಟ್ ಮೂಲಕ ನಿರ್ಣಯಿಸುವುದು, ಕೆಲಸ ಮಾಡದ ಕೋಡ್‌ನ ಭಾಗವನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ. ಆದಾಗ್ಯೂ, ಇನ್ನೂ ಒಂದೆರಡು ಕಾರ್ಯಾಚರಣೆಗಳು ಉಳಿದಿವೆ ಕರ್ಸರ್ಐಡಿ, ಇದು ಕೂಡ ಹೆಚ್ಚು ಅರ್ಥವಿಲ್ಲ.

ಎಚ್ಚರಿಕೆ N6

V1004 [CWE-476] nullptr ವಿರುದ್ಧ ಪರಿಶೀಲಿಸಿದ ನಂತರ 'ಪ್ಲೇಯರ್' ಪಾಯಿಂಟರ್ ಅನ್ನು ಅಸುರಕ್ಷಿತವಾಗಿ ಬಳಸಲಾಗಿದೆ. ಸಾಲುಗಳನ್ನು ಪರಿಶೀಲಿಸಿ: 2085, 2094. libopenrct2 Network.cpp 2094

void Network::ProcessPlayerList()
{
  ....
  auto* player = GetPlayerByID(pendingPlayer.Id);
  if (player == nullptr)
  {
    // Add new player.
    player = AddPlayer("", "");
    if (player)                                          // <=
    {
      *player = pendingPlayer;
       if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
       {
         _serverConnection->Player = player;
       }
    }
    newPlayers.push_back(player->Id);                    // <=
  }
  ....
}

ಈ ಕೋಡ್ ಸರಿಪಡಿಸಲು ತುಂಬಾ ಸುಲಭ; ನೀವು ಅದನ್ನು ಮೂರನೇ ಬಾರಿ ಪರಿಶೀಲಿಸಬೇಕಾಗಿದೆ ಆಟಗಾರ ಶೂನ್ಯ ಪಾಯಿಂಟರ್‌ಗೆ, ಅಥವಾ ಷರತ್ತುಬದ್ಧ ಹೇಳಿಕೆಯ ದೇಹಕ್ಕೆ ಸೇರಿಸಿ. ನಾನು ಎರಡನೇ ಆಯ್ಕೆಯನ್ನು ಸೂಚಿಸುತ್ತೇನೆ:

void Network::ProcessPlayerList()
{
  ....
  auto* player = GetPlayerByID(pendingPlayer.Id);
  if (player == nullptr)
  {
    // Add new player.
    player = AddPlayer("", "");
    if (player)
    {
      *player = pendingPlayer;
      if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
      {
        _serverConnection->Player = player;
      }
      newPlayers.push_back(player->Id);
    }
  }
  ....
}

ಎಚ್ಚರಿಕೆ N7

V547 [CWE-570] ಅಭಿವ್ಯಕ್ತಿ 'ಹೆಸರು == nullptr' ಯಾವಾಗಲೂ ತಪ್ಪಾಗಿರುತ್ತದೆ. libopenrct2 ServerList.cpp 102

std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
  auto name = json_object_get(server, "name");
  .....
  if (name == nullptr || version == nullptr)
  {
    ....
  }
  else
  {
    ....
    entry.name = (name == nullptr ? "" : json_string_value(name));
    ....
  }
  ....
}

ನೀವು ಓದಲು ಕಷ್ಟಪಡುವ ಕೋಡ್ ಅನ್ನು ಒಂದೇ ಹೊಡೆತದಲ್ಲಿ ತೊಡೆದುಹಾಕಬಹುದು ಮತ್ತು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಬಹುದು nullptr. ಕೋಡ್ ಅನ್ನು ಈ ಕೆಳಗಿನಂತೆ ಬದಲಾಯಿಸಲು ನಾನು ಸಲಹೆ ನೀಡುತ್ತೇನೆ:

std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
  auto name = json_object_get(server, "name");
  .....
  if (name == nullptr || version == nullptr)
  {
    name = ""
    ....
  }
  else
  {
    ....
    entry.name = json_string_value(name);
    ....
  }
  ....
}

ಎಚ್ಚರಿಕೆ N8

V1048 [CWE-1164] 'ColumnHeaderPressedCurrentState' ವೇರಿಯೇಬಲ್ ಅನ್ನು ಅದೇ ಮೌಲ್ಯವನ್ನು ನಿಗದಿಪಡಿಸಲಾಗಿದೆ. libopenrct2ui CustomListView.cpp 510

void CustomListView::MouseUp(....)
{
  ....
  if (!ColumnHeaderPressedCurrentState)
  {
    ColumnHeaderPressed = std::nullopt;
    ColumnHeaderPressedCurrentState = false;
    Invalidate();
  }
}

ಕೋಡ್ ತುಂಬಾ ವಿಚಿತ್ರವಾಗಿ ಕಾಣುತ್ತದೆ. ಸ್ಥಿತಿಯಲ್ಲಿ ಅಥವಾ ವೇರಿಯಬಲ್ ಅನ್ನು ಮರು ನಿಯೋಜಿಸುವಾಗ ಮುದ್ರಣದೋಷವಿದೆ ಎಂದು ನನಗೆ ತೋರುತ್ತದೆ ಕಾಲಮ್ ಹೆಡರ್ ಪ್ರೆಸ್ಡ್ ಕರೆಂಟ್ ಸ್ಟೇಟ್ ಮೌಲ್ಯಗಳು ಸುಳ್ಳು.

ತೀರ್ಮಾನಕ್ಕೆ

ನಾವು ನೋಡುವಂತೆ, ನಿಮ್ಮ ಟೀಮ್‌ಸಿಟಿ ಯೋಜನೆಗೆ PVS-ಸ್ಟುಡಿಯೋ ಸ್ಟ್ಯಾಟಿಕ್ ವಿಶ್ಲೇಷಕವನ್ನು ಸಂಯೋಜಿಸುವುದು ತುಂಬಾ ಸರಳವಾಗಿದೆ. ಇದನ್ನು ಮಾಡಲು, ಕೇವಲ ಒಂದು ಸಣ್ಣ ಕಾನ್ಫಿಗರೇಶನ್ ಫೈಲ್ ಅನ್ನು ಬರೆಯಲು ಸಾಕು. ಕೋಡ್ ಅನ್ನು ಪರಿಶೀಲಿಸುವುದರಿಂದ ಜೋಡಣೆಯ ನಂತರ ತಕ್ಷಣವೇ ಸಮಸ್ಯೆಗಳನ್ನು ಗುರುತಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ, ಇದು ಬದಲಾವಣೆಗಳ ಸಂಕೀರ್ಣತೆ ಮತ್ತು ವೆಚ್ಚವು ಇನ್ನೂ ಕಡಿಮೆ ಇರುವಾಗ ಅವುಗಳನ್ನು ತೊಡೆದುಹಾಕಲು ಸಹಾಯ ಮಾಡುತ್ತದೆ.

PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ
ನೀವು ಈ ಲೇಖನವನ್ನು ಇಂಗ್ಲಿಷ್ ಮಾತನಾಡುವ ಪ್ರೇಕ್ಷಕರೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲು ಬಯಸಿದರೆ, ದಯವಿಟ್ಟು ಅನುವಾದ ಲಿಂಕ್ ಅನ್ನು ಬಳಸಿ: ವ್ಲಾಡಿಸ್ಲಾವ್ ಸ್ಟೋಲಿಯಾರೋವ್. PVS-ಸ್ಟುಡಿಯೋ ಮತ್ತು ನಿರಂತರ ಏಕೀಕರಣ: ಟೀಮ್‌ಸಿಟಿ. ಓಪನ್ ರೋಲರ್ ಕೋಸ್ಟರ್ ಟೈಕೂನ್ 2 ಯೋಜನೆಯ ವಿಶ್ಲೇಷಣೆ.

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ