MacOS에서 간단한 gStreamer 파일을 실행하려는 데 애로 사항이 많네. 

 

컴파일까지야 어떻게든 했는데, 실행하려고 하니 에러가 발생하네. Dynamic Library를 찾지를 못 하는군. 

생성된 실행 파일을 `otool -L` 로 확인해 보니, gStreamer 의 참조 경로가 이렇게 되어 있네. 

 

```

 @rpath/libgstreamer-1.0.0.dylib (compatibility version 2205.0.0, current version 2205.0.0)

```

 

어쨌든, 원래는 /Library/Framework 폴더에 gStreamer가 복사되어 있는데. 해당 폴더는 또 Dynamic Library 경로에 추가되어 있지를 않고 있다. 뭐 나중을 위해서는 gStreamer Dynamic Library를 Application에 같이 패키징되어야 할 텐데, 디버깅/테스트할 때는 또 그걸 할 수 없으니. 

 

문제는 MacOS에서는 LD_LIBRARY_PATH가 동작하지 않는다. 찾아 보니 어쨌든 DYLD_FALLBACK_LIBRARY_PATH 에 추가하면 되네. Rust 나 Cargo 에서도 별 다른 방법은 없고. 환경 변수로 해당 폴더를 추가해주면 된다. 

 

실행하고 나면 참조되는 gObject 라이브러리 등이 중복되어 있다고 나오는데, 그건 무시하면 되고... 

 

그리고 나서는 다시 SSL Error가 발생하고, 이것 역시 Dynamic Library 경로 문제 같은데. 어쨌든 개발 시에만 발생할 문제로 보인다. 

 

GIO_EXTRA_MODULES 에 gstreamer 라이브러리의 gio/modules 를 할당해주면 문제 없이 실행된다. 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

2023. 3월 현재 기준으로.. 

 

여기 저기에 Conda를 사용해야 하네, 뭐네 여러가지 이야기가 많지만, 그건 작년 기준이고.

현재는 다음 TensorFlow 패키지만 설치한다. 

 

1. TensorFlow MacOS 버전 

   - tensorflow-macos => 2.10 

2. TensorFlow GPU 가속 

   - tensorflow-metal => 0.60 

 

이보다 높은 버전을 설치할 경우는 2.11의 변경 사항 때문에 GPU 가속이 동작하지 않는다. 

GPU 가속을 원하면 2.10, 0.60으로 버전을 맞추어야 한다. 

 

Apple Tensorflow 테스트 스크립트를 실행했을 때. 맥북 M2 기준으로 4배 정도 속도 차이가 난다. 

- CPU로 : 408초

- GPU로 : 90초 

 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

이제 내가 축구하는 건 시간도 없고, 나이도 없고 하기가 힘들다. 나의 기대를 대신해서 나의 주니어가 축구하는 시간이 왔다. 

 

애들에게 축구를 시키자니 장비가 문제다 그래서 다른 사람들을 위해서 초등학교 이전, 유치원 애들, 다섯살, 여섯살 애들의 장비 구입 경험을 좀 써본다. 뭐 비교 같은 건 어차피 사람들이 잘 알지도 못 하고, 알려줘도 가려듣기도 힘드니 그냥 패스한다. 

 

여기선 그냥 데카트론을 외친다... 그냥 데카트론... 엄청 강조다.. 

 

초등학교 이전 장비는 그냥 데카트론 외에는 거의 없다고 보면 된다. 지방에 있더라도 그냥 데카트론 한 번 구경 가는 것도 괜찮을 거다. 데카트론에서 일단 풀 세트를 맞추고 나서 그 다음에 맘에 안 드는 거 위주로 바꾸면 된다. 

 

1. 축구화 - 이건 다른 브랜드는 사이즈가 없어서 그냥 데카트론 이외에는 선택이 없다. 아디다스, 나이키에서 축구화가 사이즈가 제대로 나오는 건 220mm 부터다. 그 이전은 그냥 데카트론 가라. 더 문제는 아디다스, 나이키 등은 와이드 핏을 찾기 어렵다. 길이 보다 너비 때문에 애들이 발 아프다. 그리고 찍찍이로 되어 애들이 혼자 신고 벗는 것도 데카트론이 좋다. 

 

2. 보호대, 양말 - 양말은 유치원 사이즈는 다른 데서 희귀품이다. 다만 데카트론의 문제는 엄청 빡빡해서 신기기가 힘들다. 그러니 보호대를 안 하면 그냥 양말 시키는 것도 추천한다. 보호대도 조그만 사이즈는 다른 데도 찾을 수 있는데, 고급진 건 여기 외에는 없다. 

 

3. 축구공 - 이건 데카트론 거 사지 마라. 추천하는 건 스타스포츠의 팅매치다. 축구공 무게가 다르다. 3호 기준으로 통상 310g 전후인데, 팅 매치가 290g 전후다. 20g 아무 것도 아닌 것 같지만, 엄청 차이 크게 난다. 애들이 공 무게를 못 이기는 데 20g 정도면 엄청 큰 차이다.  내가 차도 무게감이 다르다. 축구에 진심이면 가벼운 공 사주는 게 좋다. 배우는 속도가 다르다. 

 

그 외에 축구 공 주머니, 휴대용 축구 골대나 콘, 기타 용품도 괜찮다. 다만 펌프는 약간 별로더라. 

 

 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

맥북 에어 M1, M2는 모니터를 하나만 지원한다고 스펙에 지정되어 있습니다. 공식적으로 듀얼 모니터를 지원하지 않는 거죠. 다만 이를 우회하기 위한 방법이 있습니다. DisplayLink를 지원하는 어댑터 또는 허브를 사용하면 됩니다. 

사용 방법이야 다른 곳에서 많이 기술되어 있고, 어떤 제품을 사야 되느냐 때문에 고민을 좀 했습니다. 

 

DisplayLink를 지원하는 제품 찾기 

Synaptics에서 DisplayLink Chipset 및 관련 기술의 소유권을 가지고 있습니다. 그래서 관련된 제품을 Synaptics 사이트에서 찾을 수 있습니다. 다만 국내에서 판매되는 제품들은 나와 있지 않은 경우가 많습니다. 

 

https://www.synaptics.com/products/displaylink-graphics/displaylink-products-list?field_displaylink_category_value=usb_adapters 

 

DisplayLink Products list | Synaptics

Diamond Wireless Vstream USB 2.0 to HDMI/VGA Transmitter and Receiver Adapter Kit Max Resolution : 1920 × 1080 (Full HD)

www.synaptics.com

 

칩셋에 따른 성능 

위의 사이트에서 찾다 보니 어댑터 별로 해상도가 다르고, 지원 모니터도 다르고 복잡하더군요. 그래서 좀 더 찾아보니, 내장된 칩셋에 따라서 다 다릅니다. 국내에서 판매되는 어댑터들은 대부분 HD 해상도만 지원합니다. 

어쨌든 저는 DL-5XXX 계열로 하여, 4K 해상도 지원되는 제품을 Amazon에서 구매하였습니다. 국내 제품들은 대체로 DL-1xxx 제품을 사용해서 HD 해상도만 지원됩니다. 

 

 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

이게 뭔가 독특한게 사용자가 정의한 것과 시스템 환경 변수가 사용 방법이 다르다. 

소스 코드를 뜯어봐야 알겠지만, 사용자가 정의한 환경 변수는 별도의 env 변수에 넣는 걸로 보인다. 

 

그래서 사용 방법이 달라진다. 웃긴 건 이걸 적어 놓은 게 아무 데도 없다는 거다. -.-

 

 

    environment {
        commitHash = ""         // 
    }

	pipeline {
    
    	...
        
    	stage('Some') {
        
        	script {
            	echo "${commitHash}" 		// Error 
                echo "${env.commitHash}" 	// Work well
                
                echo "${BRANCH_NAME}"		// work well
        
        
        }
        
        ...
    }

	

WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

회사 보안 정책으로 인해서 여러 가지 보안 SW를 설치하고 사용합니다. 그 중 잘 만든 것도 있고, 쓰레기 같은 프로그램도 있습니다. 쓰레기 류 중의 하나가 V3죠. 

 

NPM과 Gradle을 CI를 돌리거나, NPM Install을 하게 되면, 대량의 파일 복사를 하게 됩니다. 특히 NPM은 Directory나 파일의 Link를 Rename 해 놓은 후, 나중에 영구 삭제하는 과정을 거치는 걸로 보입니다. 

 

문제는 NPM이 파일을 처리하고 나서 바로 Rename에 들어가게 되는데, NPM이 처리한 파일을 V3가 붙잡고 있습니다. 그래서 rename하는 과정에 예외가 발생합니다. 아주 거지 같죠. 

 

회사 직원들이 Jenkins가 자꾸 실패가 뜬다는 말에 살펴 보니, 또 V3가 문제인 것 같습니다. 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

Lezyne의 펌프를 2개 가지고 있다. 하나는 CNC Floor Drive, 다른 하나는 Micro Floor Drive다. 가격은 Lezyne이 표방하는 바대로 더럽게 비싸다. 

 

어쨌든 더럽게 비싼 이 펌프 2개는 다 고장 상태였다. CNC Floor Drive는 펌프를 아무리 펌프질해도 에어가 나오지 않고, Micro Floor Drive는 Presta 노즐을 오픈 안 한 상태로 눌러줬더니 ABS 버튼 자리가 그냥 터져 버린다. 그리고 펌프 게이지도 제대로 동작하지 않고. 

 

찾아보니 펌프질 안 되는 건 O Ring 문제로 고질적이고, ABS 버튼 터진 거야 그렇다 치고.. 

 

근데 말 그대로 더럽게 잘 만든 펌프라며... 일반인이 펌프를 사용해도 일년에 몇 번 사용할까? 내 생각에 한 30번 사용하고 O Ring이 날아간 거다. 뭔 고급 펌프가 30번 펌프질 하면 소모품 교체냐? 더 짜증 나는 건 한국 판매처는 문의해도 답변도 없다. 그래서 그냥 공구상에서 널려 있는 하나에 50원짜리 O Ring 사서 교체 했다. 아주 잘 돌아가네.. ㅎㅎ

ABS 버튼도 세게 누른 것도 아닌 데 버튼의 고정 나사가 날아갔다. 그냥 공기압에 터져 버린거다. 

 

고급 브랜드를 가장한 싸구려 품질 수준이다. 다음부터는 이쪽 제품은 안 사는 걸로 마음을 굳혔다. 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

UI 표시가 제대로 되지 않아서 문제점을 찾다보니 객체가 이유없이 생성, 파괴를 반복한다. 

문제는 해당 객체가 State를 유지하고 있다는 거다. Stateless하면 문제 없을 텐데 상태가 있다 보니 재생성되면 UI 요소가 사라져 버린다. 내가 짠 부분이 아니라 수정하진 않는다. 

 

<ng-container *ngFor="let server of servers$|async;">
  .... something ..... 
</ng-container>

문제가 되는 부분을 보니 ngFor와 NgRx Store가 같이 쓰인다. 두 가지가 복합되서 문제가 발생했다. 

1. NgRx Store에서 State를 가져오는데, 그 때마다 Object Reference가 변경된다. 

2. ngFor는 자기 하부의 DOM을 Object Reference에 의거해서 관리한다. 

두 가지가 조합되면 ngFor는 자기 하부의 모든 DOM을 싹 날리고 재생성하는 일을 반복한다. 

 

그래서 아래와 같이 변경한다. 이렇게 하면 ngFor는 trackBy에 의거해서 자신의 하부의 DOM을 생성한다. 

<ng-container *ngFor="let server of servers$|async; trackBy: trackByGuid">
  .... something ..... 
</ng-container>



  public trackByGuid(index: number, server: Server) {
    return server.guid;
  }

 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

Angular에서 주기적 polling 같은 걸 rxjs, ngrx 같은 걸로 구현해 놓으면 테스트에 실패가 발생한다. 마지막에 다음과 같은 에러가 발생하면서 문제가 발생한다. 주기적 Timer 들이 MicroTask로 계속 남아 있으면서 에러가 발생하는 걸로 보인다. 

    8 periodic timer(s) still in the queue.

      at node_modules/zone.js/dist/fake-async-test.js:617:31
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:386:30)
      at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:117:43)
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:385:36)
      at Zone.run (node_modules/zone.js/dist/zone.js:143:47)

이걸 해결하려면 test의 마지막에 discardPeriodicTasks()를 호출해주면, 정리 작업이 완료된다. 

 

또 한 가지 에러는 테스트 안의 expect의 assertion이 fail하면, 코드에 아무 문제가 없는 데도 아래와 같은 에러가 발생한다. 테스트가 정상적으로 완료되면 아래 에러는 없어진다. 

    Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.

 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,

Jest에 Angular FlexLayout이 적용된 컴포넌트를 테스트하니 아래와 같은 에러가 발생한다. 

    TypeError: getComputedStyle(...).getPropertyValue is not a function

      at StyleUtils.lookupStyle (node_modules/@angular/src/lib/core/style-utils/style-utils.ts:94:47)
      at StyleUtils.hasWrap (node_modules/@angular/src/lib/core/style-utils/style-utils.ts:65:17)
      at DefaultFlexDirective.BaseDirective2.hasWrap (node_modules/@angular/src/lib/core/base/base2.ts:137:24)

 

한참을 찾아봐도 에러 원인을 알 수가 없다. 당연히 나지 말아야 할 에러니까.

 

찾다 보니 Jest는 DOM 관련된 모듈로 JSDOM을 사용한다. 문제는 JSDOM이 getComputedStyle에 대한 구현이 없는 모양이다. 그래서 jest-preset-angular에서는 setup-jest.ts에 다음과 같이 mocking을 해놨다. 위에서 발생한 에러를 쳐다보면 당연히 구현이 없으니 에러가 발생한다. 

Object.defineProperty(window, 'getComputedStyle', {
  value: () => ['-webkit-appearance'],
});

그래서 다음과 같이 mocking한 걸 변경한다. 

Object.defineProperty(window, 'getComputedStyle', {
  value: () => ({
      getPropertyValue: (prop) => {
          return '';
      }
  })
});

 

References

 


WRITTEN BY
HanDDol
여행이란 건 말이지. 첫 걸음을 내딜 때는 모든 게 낯설고.. 그리고 점점 더 낯선 세상에 익숙해지면서 세상의 모든 곳이 고향처럼 느껴진다. 고향으로 돌아오는 여행의 마지막 걸음에는 나의 고향이 더 이상 익숙한 곳이 아닌 낯선 곳임을 알게 된다.

,